- 1、包
- 1.1、需求引出
- 1.2、包的三大作用
- 1.3、基本语法
- 1.4、包的本质分析
- 1.5、包的命名
- 1.6、常用的包
- 1.7、如何引入包
- 1.8、注意事项和使用细节
- 2、访问修饰符
- 2.1、定义
- 2.2、4 种访问修饰符的访问范围
- 2.3、使用的注意事项
- 2.4、代码实现
- 3、面向对象编程三大特征
- 3.1、封装
- 3.1.1、定义
- 3.1.2、封装的优势
- 3.1.3、封装的实现步骤
- 3.1.4、将构造器和 setXxx 结合
- 3.2、继承
- 3.2.1、定义
- 3.2.2、定义继承的基本语法
- 3.2.3、代码实现
- 3.2.4、继承给编程带来的便利
- 3.2.5、继承的细节问题
- 3.2.6、继承的本质分析
1.3、基本语法
- 区分相同名字的类
- 当类很多时,可以很好的管理类【看Java API文档】
- 控制访问范围
package com.helloedu; 说明: 1、package: 关键字, 表示打包 2、com.helloedu: 表示包名1.4、包的本质分析
1.6、常用的包只能包含数字、字母、下划线、小圆点,但不能用数字开头,不能是关键字或保留字
demo.class.exec1 // 错误 class是关键字
demo.12a // 错误 12a是数字开头
demo.ab12.oa // 对
命名规范:
一般是小写字母+小圆点
例如:com.xxx.oa.model;
com.xxx.oa.controller;
举例:
com.sina.crm.user; // 用户模块
com.sina.crm.order; // 订单模块
com.sina.crm.utils; // 工具类
1.7、如何引入包一个包下,包含很多的类,java 中常用的包有:
- java.lang.* // lang 包是基本包,默认引入,不需要再引入
- java.util.* // util 包,系统提供的工具包,工具类,使用 Scanner
- java.net.* // 网络包,网络开发
- java.awt.* // 是做 java 的界面开发,GUI
// 一个类中最多只有一句 package
package com.use_;
// 建议: 我们需要使用到哪个类, 就导入哪个类即可, 不建议使用 * 导入
// import 指令位置放在 package 的下面, 在类定义前面, 可以有多句且没有顺序要求
import java.util.Arrays; // 表示只会引入 java.util 包下的 Arrays
import java.util.*; // 表示将 java.util 包下的所有类都引入(导入)
public class Sort_ {
public static void main(String[] args) {
int[] arrList = {1, -2, 99, -105, 82, 30, -3, 0, 5, 29};
// 系统提供了相关的类, 可以方便完成排序 (Arrays 类)
Arrays.sort(arrList);
for (int i = 0; i < arrList.length; i++) {
System.out.print(arrList[i] + "t");
}
}
}
1.8、注意事项和使用细节
2、访问修饰符
2.1、定义
2.2、4 种访问修饰符的访问范围 2.3、使用的注意事项java 提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围):
- 公开级别:用 public 修饰,对外公开
- 受保护级别:用 protected 修饰,对子类和同一个包中的类公开
- 默认级别:没有修饰符号,向同一个包的类公开
- 私有级别:用 private 修饰,只有类本身可以访问,不对外公开
2.4、代码实现
- 修饰符可以用来修饰类中的属性,成员方法及类
- 只有默认的和public才能修饰类,并且遵循上述访问权限的特点
- 成员方法的访问规则和属性完全一样
TestClass.java
package access;
import access1.TestClass3;
import access1.TestClass4;
public class TestClass {
public int n1 = 10;
protected int n2 = 20;
int n3 = 30;
private int n4 = 40;
public void m1() {
System.out.println("TestClass中 public m1 方法");
}
protected void m2() {
System.out.println("TestClass中 protected m2 方法");
}
void m3() {
System.out.println("TestClass中 默认 m3 方法");
}
private void m4() {
System.out.println("TestClass中 private m4 方法");
}
public static void main(String[] args) {
// 在同类中测试
// 结论: 所有属性和方法都能正常访问
TestClass testClass = new TestClass();
System.out.println(testClass.n1);
System.out.println(testClass.n2);
System.out.println(testClass.n3);
System.out.println(testClass.n4);
testClass.m1();
testClass.m2();
testClass.m3();
testClass.m4();
System.out.println("=====");
// 在同一个包中, 不同的类中测试 测试 TestClass1 类
// 结论: private 属性和方法不能正常访问
TestClass1 testClass1 = new TestClass1();
System.out.println(testClass1.h1);
System.out.println(testClass1.h2);
System.out.println(testClass1.h3);
// System.out.println(testClass1.h4); // 报错
testClass1.q1();
testClass1.q2();
testClass1.q3();
// testClass1.q4(); // 报错
System.out.println("=====");
// 在同一个包中, 子类继承父类 测试 测试 TestClass2 类
// 结论: private 属性和方法不能正常访问
TestClass2 testClass2 = new TestClass2();
System.out.println(testClass2.h1);
System.out.println(testClass2.h2);
System.out.println(testClass2.h3);
// System.out.println(testClass2.h4); // 报错
testClass2.q1();
testClass2.q2();
testClass2.q3();
// testClass2.q4(); // 报错
System.out.println("=====");
// 在不同的包中, 子类继承父类 测试 测试 TestClass3 类
// 结论: 默认和private 属性和方法不能正常访问
TestClass3 testClass3 = new TestClass3();
System.out.println(testClass3.n1);
System.out.println(testClass3.n2);
// System.out.println(testClass3.n3); // 错误
// System.out.println(testClass3.n4); // 错误
testClass3.m1();
testClass3.m2();
// testClass3.m3(); // 错误
// testClass3.m4(); // 错误
System.out.println("=====");
// 在不同的包中, 测试 TestClass4 类
// 结论: protected、默认private 属性和方法不能正常访问, 只有公开类的属性和方法可以正常访问
TestClass4 testClass4 = new TestClass4();
System.out.println(testClass4.v1);
// System.out.println(testClass4.v2); // 报错
// System.out.println(testClass4.v3); // 报错
// System.out.println(testClass4.v4); // 报错
testClass4.c1();
// testClass4.c2(); // 报错
// testClass4.c3(); // 报错
// testClass4.c4(); // 报错
}
}
TestClass1.java
package access;
// 在同一个包中, 不同的类中测试
public class TestClass1 {
public int h1 = 100;
protected int h2 = 200;
int h3 = 300;
private int h4 = 400;
public void q1() {
System.out.println("TestClass1中 public q1 方法");
}
protected void q2() {
System.out.println("TestClass1中 protected q2 方法");
}
void q3() {
System.out.println("TestClass1中 默认 q3 方法");
}
private void q4() {
System.out.println("TestClass1中 private q4 方法");
}
}
TestClass2.java
package access;
public class TestClass2 extends TestClass1{
}
TestClass3.java
package access1;
import access.TestClass;
public class TestClass3 extends TestClass {
}
TestClass4.java
package access1;
public class TestClass4 {
public int v1 = 1000;
protected int v2 = 2000;
int v3 = 3000;
private int v4 = 4000;
public void c1() {
System.out.println("TestClass4中 public c1 方法");
}
protected void c2() {
System.out.println("TestClass4中 protected c2 方法");
}
void c3() {
System.out.println("TestClass4中 默认 c3 方法");
}
private void c4() {
System.out.println("TestClass4中 private c4 方法");
}
}
3、面向对象编程三大特征
3.1、封装 3.1.1、定义 3.1.2、封装的优势 3.1.3、封装的实现步骤封装、继承和多态
public class Encapsulation {
public static void main(String[] args) {
Person person = new Person();
person.setName("张三");
person.setAge(150); // 年龄150不在范围内, 用默认值 18
person.setSalary(1000.98);
System.out.println(person.info());
}
}
// 不能随便查看人的年龄, 工资等隐私, 并对设置的年龄进行合理的验证
// 年龄合理就设置, 否则给默认年龄 18, 年龄必须在 1-120, 工资不能直接查看, name 的长度在 2-6 字符之间
class Person {
public String name;
private int age;
private double salary;
public Person() {
}
public Person(String name, int age, double salary) {
// 我们可以将 set 方法写在构造器中, 这样仍然可以验证
setName(name);
setAge(age);
setSalary(salary);
}
//自己写 setXxx 和 getXxx 太慢, 我们使用快捷键
// 然后根据要求来完善我们的代码
// 加入对数据的校验, 相当于增加了业务逻辑
public String getName() {
return name;
}
public void setName(String name) {
if (name.length() >= 2 && name.length() <= 6) {
this.name = name;
} else {
System.out.println("名字的长度不对, 需要(2-6)个字符, 默认名字");
this.name = "无名";
}
}
public int getAge() {
return age;
}
public void setAge(int age) { // 如果是合理范围
if (age >= 1 && age <= 120) {
this.age = age;
} else {
System.out.println("你设置年龄不对, 需要在 (1-120), 给默认年龄 18");
this.age = 18; // 给一个默认年龄
}
}
public double getSalary() {
// 可以这里增加对当前对象的权限判断
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
// 写一个方法, 返回属性信息
public String info() {
return "信息为 name=" + name + " age=" + age + " 薪水=" + salary;
}
}
3.1.4、将构造器和 setXxx 结合
public Person(String name, int age, double salary) {
// 我们可以将 set 方法写在构造器中, 这样仍然可以验证
setName(name);
setAge(age);
setSalary(salary);
}
3.2、继承
3.2.1、定义
3.2.2、定义继承的基本语法 3.2.3、代码实现继承可以解决代码复用, 让我们的编程更加靠近人类思维, 当多个类存在相同的属性(变量)和方法时, 可以从这些类中抽象出父类, 在父类中定义这些相同的属性和方法, 所有的子类不需要重新定义这些属性和方法, 只需要通过 extends 来 声明继承父类即可
Extends.java
package com.jm;
public class Extends {
public static void main(String[] args) {
Pupil pupil = new Pupil();
pupil.name = "张三";
pupil.age = 18;
pupil.setScore(95);
pupil.testing();
pupil.showInfo();
System.out.println("=====");
Graduate graduate = new Graduate();
graduate.name = "李四";
graduate.age = 20;
graduate.setScore(100);
graduate.testing();
graduate.showInfo();
}
}
// 父类, 是 Pupil 和 Graduate 的父类
class Student {
// 共有属性
public String name;
public int age;
private double score;//成绩
// 共有的方法
public void setScore(double score) {
this.score = score;
}
public void showInfo() {
System.out.println("学生名 " + name + " 年龄 " + age + " 成绩 " + score);
}
}
Pupil.java
package com.jm;
public class Pupil extends Student { // 子类Pupil 继承父类Student
public void testing() {
System.out.println("小学生 " + name + " 正在考小学数学..");
}
}
Graduate.java
package com.jm;
public class Graduate extends Student { // 子类Graduate 继承父类Student
public void testing() {
System.out.println("大学生 " + name + " 正在考大学数学..");
}
}
3.2.4、继承给编程带来的便利
3.2.5、继承的细节问题
- 代码的复用性提高了
- 代码的扩展性和维护性提高了
- 子类继承了所有的属性和方法, 非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访问, 要通过父类提供公共的方法去访问
- 子类必须调用父类的构造器, 完成父类的初始化
- 当创建子类对象时, 不管使用子类的哪个构造器, 默认情况下总会去调用父类的无参构造器, 如果父类没有提供无参构造器, 则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作, 否则, 编译不会通过
- 如果希望指定去调用父类的某个构造器, 则显式的调用一下:super(参数列表)
- super 在使用时, 必须放在构造器第一行(super 只能在构造器中使用)
- super() 和 this() 都只能放在构造器第一行, 因此这两个方法不能共存在一个构造器
- java 所有类都是 Object 类的子类, Object 是所有类的基类.
- 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)
- 子类最多只能继承一个父类(指直接继承), 即 java 中是单继承机制
- 不能滥用继承, 子类和父类之间必须满足 is-a 的逻辑关系
ExtendsDetail.java
package com.jm;
public class ExtendsDetail {
public static void main(String[] args) {
System.out.println("===第 1 个对象====");
Sub sub = new Sub(); // 创建了子类对象 sub
System.out.println("===第 2 个对象====");
Sub sub2 = new Sub("jack"); // 创建了子类对象 sub2
System.out.println("===第 3 对象====");
Sub sub3 = new Sub("king", 10); // 创建了子类对象 sub2
sub.sayOk();
}
}
Topbase.java
package com.jm;
public class Topbase {
public Topbase() {
super(); // Object 的无参构造器
System.out.println("构造器 Topbase() 被调用...");
}
}
base.java
package com.jm;
public class base extends Topbase { //父类
// 4 个属性
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
public base() {
// 无参构造器
System.out.println("父类 base()构造器被调用....");
}
public base(String name, int age) { // 有参构造器
// 默认 super()
System.out.println("父类 base(String name, int age)构造器被调用....");
}
public base(String name) { // 有参构造器
System.out.println("父类 base(String name)构造器被调用....");
}
//父类提供一个 public 的方法, 返回了 n4
public int getN4() {
return n4;
}
public void test100() {
System.out.println("test100");
}
protected void test200() {
System.out.println("test200");
}
void test300() {
System.out.println("test300");
}
private void test400() {
System.out.println("test400");
}
// call
public void callTest400() {
test400();
}
}
Sub.java
package com.jm;
// 输入 ctrl + H 可以看到类的继承关系
public class Sub extends base { // 子类
public Sub(String name, int age) {
// 1. 调用父类的无参构造器, 如下或者什么都不写, 默认就是调用super()
// super(); // 父类的无参构造器
// 2. 调用父类的 base(String name) 构造器
// super("tom");
// 3. 调用父类的 base(String name, int age) 构造器
super("king", 20);
// 细节: super 在使用时, 必须放在构造器第一行
// 细节: super() 和 this() 都只能放在构造器第一行, 因此这两个方法不能共存在一个构造器
// this() 不能再使用了
System.out.println("子类 Sub(String name, int age)构造器被调用....");
}
public Sub() { // 无参构造器
// super(); // 默认调用父类的无参构造器
super("smith", 10);
System.out.println("子类 Sub()构造器被调用....");
}
// 当创建子类对象时, 不管使用子类的哪个构造器, 默认情况下总会去调用父类的无参构造器
public Sub(String name) {
super("tom", 30);
// do nothing...
System.out.println("子类 Sub(String name)构造器被调用....");
}
public void sayOk() {
// 子类方法
// 非私有的属性和方法可以在子类直接访问
// 但是私有属性和方法不能在子类直接访问
System.out.println(n1 + " " + n2 + " " + n3);
test100();
test200();
test300();
// test400(); 错误
// 要通过父类提供公共的方法去访问
System.out.println("n4=" + getN4());
callTest400();
}
}
3.2.6、继承的本质分析
当子类对象创建好后,建立查找的关系
ExtendsTheory.java
package com.jm;
public class ExtendsTheory {
public static void main(String[] args) {
Son son = new Son(); // 内存的布局
// 要按照查找关系来返回信息
// (1) 首先看子类是否有该属性
// (2) 如果子类有这个属性, 并且可以访问, 则返回信息
// (3) 如果子类没有这个属性, 就看父类有没有这个属性(如果父类有该属性, 并且可以访问, 就返回信息..)
// (4) 如果父类没有就按照(3)的规则, 继续找上级父类, 直到 Object...
System.out.println(son.name); // 返回就是大头儿子
// System.out.println(son.age); // 报错
System.out.println(son.getAge()); // 返回的就是 39
System.out.println(son.hobby); // 返回的就是旅游
}
}
class GrandPa { // 爷类
String name = "大头爷爷";
String hobby = "旅游";
}
class Father extends GrandPa { //父类
String name = "大头爸爸";
private int age = 39;
public int getAge() {
return age;
}
}
class Son extends Father { //子类
String name = "大头儿子";
}
子类创建的内存布局



