通过之前对 JAVA基础 —— 面向对象 以及 JAVA基础 —— 面向对象内存图 的学习。
接下来我们将会进一步学习面向对象进阶的相关知识点。
static | JAVA基础 (面向对象进阶)—— Static |
继承 | JAVA基础 (面向对象进阶)—— 继承 |
多态 | JAVA基础 (面向对象进阶)—— 多态 |
包、final、权限修饰符、代码块、抽象类和抽象方法方法 | JAVA基础(面向对象进阶) —— 包、final、权限修饰符、代码块、抽象类和抽象方法方法 |
接口 | JAVA基础 (面向对象进阶)—— 接口 |
内部类 | JAVA基础 (面向对象进阶)—— 内部类 |
目录
一、包
包就是文件夹,用来管理各种不同功能的Java类,方便后期代码维护。
- 包名的规则:公司域名反写 + 包的作用,需要全部英文小写,见名知意。
使用其他类的规则:
- 使用同一个包中的类时,不需要导包
- 使用java.lang包中的类时,不需要导包。
- 其他情况都需要导包。
- 如果同时使用两个包中的同名类,需要用全类名。(全类名:包名 + 类名)
代码分析:
//com.JavaWork01 和 com.JavaWork02 包中的Teacher类
package com.JavaWork01;
package com.JavaWork02;
public class Teacher {
private String name;
private int age;
public Teacher() {}
public Teacher(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//com.JavaLearn 包中的Student 类
package com.JavaLearn;
public class Student {
private String name;
private int age;
public Student() {}
public Student(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//com.JavaLearn 包中的Test测试类
package com.JavaLearn;
import com.JavaWork01.Teacher;
public class Test {
public static void main(String[] args) {
// 创建对象
// 1.使用同一个包中的类不需要导包
Student s = new Student();
s.setName("张三");
s.setAge(23);
System.out.println(s.getName() + "," + s.getAge());
// 2.java.lang包中 我们知道有一种:String字符串
// 此时同样没有导包
String str = "abc";
System.out.println(str);
// 3.使用其他包中类需要导包
// import com.JavaWork.Teacher;
Teacher t = new Teacher();
// 4.同时使用两个包中同名类,需要全类名
// Teacher t1 = new Teacher();
// 这样写不知道t2来自于哪个包中的teacher类
// Teacher t2 = new Teacher();
com.JavaWork01.Teacher t1 = new com.JavaWork01.Teacher();
com.JavaWork02.Teacher t2 = new com.JavaWork02.Teacher();
}
}
二、final关键字
见字知意: 被final关键字修饰的类就是最终类,是不可被改变的。
final可以修饰:
方法 表明该方法是最终方法,不能被重写 类 表明该类是最终类,不能被继承 变量 叫做常量,只能被赋值一次,一旦赋值后就不能再被改变
package finalTest;
public class Test {
public static void main(String[] args) {
//final修饰变量a
final int a= 10;
System.out.println(a);
//此时修改a值报错
//被final修饰的a为常量
a = 20;
//常量:在实际开发中,常量一般作为系统的配置信息,方便维护,提高可读性。
//常量的命名规范:
//单个单词:全部大写
//多个单词:全部大写,单词之间用下划线隔开
}
//final修饰父类
final class Fu {
//父类方法用final关键字修饰
public final void show() {
System.out.println("父类show方法");
}
}
//子类继承父类报错
//父类是最终类,不能被子类继承
class Zi extends Fu{
@Override
//子类show方法报错
//说明被final修饰父类方法不能被子类继承
public void show() {
System.out.println("子类show方法");
}
}
}
final关键字细节:
final修饰的变量:
基本数据类型 变量存储的数据值不能发生发生改变。 引用数据类型 变量存储的地址值不能发生改变,内部的属性值可以改变。
public class Test {
public static void main(String[] args) {
final double pai = 3.14;
//报错!
//被pai修饰的基本数据类型pai为常量
//其数据值不能被改变
double pai = 3.1415;
final Student s =new Student("zhangsan",23);
//被final修饰引用数据类型可以修改数据值
s.setName("lisi");
s.setAge(24);
//报错!
//被final修饰的引用数据类型地址值不能改变
s = new Student();
}
}
三、权限修饰符
- 权限修饰符:是用来控制一个成员能够被访问的范围的。
- 可以修饰成员变量:方法、构造方法、内部类。
1. 权限修饰符的分类
有四种范围由小到大为(private < 空着不写 < protected < public)
修饰符 | 同一个类中 | 同一个包中其他类 | 不同包下的子类 | 不同包下的无关类 |
private | ✔ | |||
空着不写 (默认) | ✔ | ✔ | ||
protected | ✔ | ✔ | ✔ | |
public | ✔ | ✔ | ✔ | ✔ |
2. 权限修饰符的使用规则
实际开发中,一般只用private和public
- 成员变量私有
- 方法公开
特例:如果方法中的代码时抽取其他方法中共性代码,这个方法一般也私有。
四、代码块
1. 局部代码块
作用:提前结束变量的生命周期 | |
最本质特征:节约内存,变量不再使用就立马让其消失,如今使用不大。 |
2. 构造代码块
构造代码块就是写在成员位置的代码块,优先于构造方法执行。 | |
此时发现空参构造和带参构造出现重复sysout语句。 (因此我们新增了构造代码块) | |
作用:可以将多个构造方法中重复的代码抽取出来。 执行时机:我们在创建本类对象先执行构造代码块再执行构造方法。 | |
当多个构造方法都有重复代码时,我们可以如下操作: |
3. 静态代码块
格式:static{ }
特点:需要通过satic关键字修饰,随着类的加载而加载,并且自动触发,只执行一次。
使用场景:在类加载的时候,做一些数据初始化的时候使用。
五、抽象类和抽象方法
1. 抽象类和抽象方法的定义
- 抽象方法:将共性的行为(方法)抽取到父类之后。
由于每一个子类执行的内容是不一样的。
所以,在父类中不能确定具体的方法体。
该方法就可以定义为抽象方法。
- 抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类。
- 作用:抽取共性时,无法确定方法体,就把方法定义为抽象的;强制让子类按照某种格式重写;抽象方法所在的类,必须是抽象类。
2. 抽象类和抽象方法的定义格式
- 抽象方法的定义格式:
public abstract 返回值类型 方法名(参数列表);
- 抽象类的定义格式:
public abstract class 类名 { }
例如:
3. 抽象类和抽象方法的注意事项
- 抽象类不能实例化(实例化 就是 创建对象)。
- 抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类。
- 可以有构造方法
- 抽象类的子类:① 要么重写抽象类中所有抽象方法;②要么是抽象类。
//父类 Person.java
public abstract class Person {
private String name;
private int age;
//可以有构造方法
//思考:抽象类不能创建对象,那我们要构造方法干什么?
//答案:当创建子类对象时,给属性进行赋值的。
public Person() {}
public Person(String name,int age) {
this.name = name;
this.age = age
}
//有抽象方法的类一定是抽象类
public abstract void work();
//抽象类中不一定有抽象方法
public void sleep() {
System.out.println("睡觉");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//子类 Student.java
public class Student extends Person{
public Student() {}
public Student(String name,String age) {
super(name,age);
}
//重写父类方法
@Override
public void work() {
System.out.println("学生的工作是学习");
}
}
//测试类
public class Test {
public static void main(String[] args) {
// 创建对象
// 报错: 抽象类不能实例化
// Person p = new Person();
Student s = new Student("张三", 23);
System.out.println(s.getName() + "," + s.getAge());
}
}
4. 练习: 编写带有抽象类的标准Javabean类
动物 属性 行为 青蛙frog 名字,年龄 吃虫子,竭水 狗Dog 名字,年龄 吃骨头,喝水 山羊Sheep 名字,年龄 吃,喝水
//父类 Animal.java
public abstract class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void drink() {
System.out.println("动物在喝水");
}
public abstract void eat();
/*
* public void eat() {
* //此时发现写什么都不对
* //不同动物吃的不一样
* System.out.println("???");
* }
*/
}
//Frog.java
public class Frog extends Animal {
public Frog() {
}
public Frog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("青蛙在吃虫子");
}
}
//Dog.java
public class Dog extends Animal {
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("狗吃骨头");
}
}
//Sheep.java
public class Sheep extends Animal{
public Sheep() {
}
public Sheep(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("山羊吃草");
}
}
//Test.java
public class Test {
public static void main(String[] args) {
Frog f = new Frog("小绿",1);
System.out.println(f.getName() + "," + f.getAge());
f.drink();
f.eat();
}
}
运行结果:
5. 抽象类和抽象方法的意义
- 疑问:
- 把子类中共性的内容抽到父类之后
- 由于方法体不确定,需要定义为抽象。子类使用时需要重写。
- 那么我们不抽取到父类,直接在子类写不是更节约代码吗?