目录
(四)面向对象
5、继承
(6)权限修饰符:
概述:
对象中的属性和方法,可以根据不同的权限修饰符来控制访问。
范围(从小到大):
public > protected > 默认(default) > private
具体范围介绍:
public:公共的,类内部,类外部都可以访问。
用处:比如封装时用于提供对外的公共访问方式。
继承时允许被继承的成员是public型
protected:受保护的,同一个类中,同一个包中的子类或其他类,不同包中的子类可以访问
default:默认权限修饰符,指不显式指出修饰符时,就是什么都不写的时候,默认是default型,同一个类,同一个包中的子类和其他类可以访问
private:私有的,仅仅允许同一个类中的访问。
用处:封装时,将不需要的成员私有化
(7)重写:
为什么要重写?
父子类继承关系中,当子类需要父类的功能,而继承的方法不能完全满足子类的需求,子类里面有特殊的功能,此时可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
重写的各个要求以及与重载的对比:
1、使用前提 重写:父子类继承关系中
重载:在同一个类中
2、权限修饰符 重写:重写方法的访问权限修饰符可以被扩大,但是不能被缩小
public > protected > default > private
重载:与权限修饰符无关
3、返回值类型 重写:方法的返回类型可以相同,也可以不同(暂时先按相同处理,后续再补充)
重载:与返回值类型无关
4、方法名 重写:子类新增方法,和从父类继承的方法,方法名完全相同
重载:方法名必须相同
5、参数列表 重写:两个方法的参数列表完全相同
重载:参数列表不同(个数或数据类型不同)
6、异常处理范围 重写:方法抛出异常类型的范围可以被缩小,但是不能被扩大(超纲内容,暂时先忽略)
重载:不关心这个,变大变小都可以
7、注解:重写要加注解@Override
这个注解是用来标识该方法是重写的方法,辅助编译器检查,编译器可以直接判断写法是否符合规范
这个注解不写也是可以的,编译器会先判断他是否有尝试重写的意图,之后再判断是否符合规范。
注意:一般情况下,子类进行方法重写时,最好方法的声明完全一致
注意事项:
1、子类继承父类,在调用方法的时候,如果子类没有重写,则调用父类方法;如果子类进行了重写,则优先调用子类的方法
2、子类中特有的方法,方法名与父类的方法名必须不同,只要相同,编译器就认为是在尝试重写,按照重写的要求来判断,从而发生编译报错。
3、子类中特有的属性,与父类具有相同的属性时,会隐藏父类。
4、特殊情况:父类中private成员不可以被重写
父类中static成员不可以被重写
父类中final成员不可以被重写
案例:
//定义父类:员工
class Employee {
//工号、姓名
private String id;
private String name;
public Employee() {}
public Employee(String id, String name) {
this.id = id;
this.name = name;
}
public void doWork() {
System.out.println("员工开始工作...");
}
}
//定义子类:程序员
class Programmer extends Employee {
//等级:初级、中级、高级、资深
private String grade;
public Programmer() {
//默认会调用父类无参构造器
//super();
}
public Programmer(String id,String name,String grade) {
//显式调用父类构造器
super(id,name);
this.grade = grade;
}
//重写方法
// @Override是注解,用于标识该方法为重写的方法,大家可以不用管
@Override
public void doWork() {
//super.doWork();
System.out.println("我是程序员,级别为" + grade + ", 开始工作:写代码");
}
}
//定义子类:经理
class Manager extends Employee {
//奖金
private double bonus;
public Manager() {
super();
}
public Manager(String id,String name,double bonus) {
super(id,name);
this.bonus = bonus;
}
//重写方法
@Override
public void doWork() {
System.out.println("我是经理,有津贴" + bonus + ", 开始工作:安排部门员工任务");
}
}
测试类:
//测试类
public class Test06_Override {
public static void main(String[] args) {
//父类对象 调用 doWork方法
Employee e = new Employee("008", "larry");
e.doWork();
System.out.println("------------");
//程序员子类对象 调用 重写方法
Programmer p = new Programmer("010", "kevin", "初级");
p.doWork();
System.out.println("------------");
//经理子类 调用 重写方法
Manager m = new Manager("006", "robin", 201.5);
m.doWork();
}
}
toString的重写:
由于Object是顶级父类,因此可以说每个类都或多或少的直接或间继承了他,可以重写Object中的方法
toString():返回对象所在的类以及他的地址值
返回类型为String,返回的格式是类名@十六进制地址
如果想要让他返回该对象的属性名及其值,可以对该方法进行重写
//toString原码
public String toString() {
//返回 "类的全包名@该对象堆空间地址(十六进制形式)"
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
//重写toString方法
@Override
public String toString() {
return "Teacher [name=" + name + ", balance=" + balance + "]";
}
(8)final关键字:
定义:
final是一个修饰符,表示最终的意思,可以用来修饰变量,方法,类。
用法:
1、final修饰类:
用final修饰的类不能被继承,也就是说这个类是没有子类的。
常见的被final修饰的类:String、Integer、Long、Double、Boolean、Character、Math等
public final class Action { } //编译报错 class Go extends Action { }
2、final修饰方法:
final修饰的方法可以被子类继承,但不能被子类重写
被final修饰的方法:Object里的wait()
public class Person { public final void print() {} } //编译报错 class Student extends Person { //从父类继承的final方法,不可以被重写 public void print() { } }
3、final修饰变量:final修饰的变量成为了常量,只能被赋值一次,第二次会报编译错误
(1)final修饰局部变量:
注意局部变量赋初值之后,不能二次赋值,当他是形参的时候,传值后就已经赋初值了。
public void print(){ final int a; a = 1;//第一次赋值 a = 2;//编译报错,不能二次赋值·】 } public void print2(final int a){ a = 1;//编译报错,当执行该方法假设为person.print2(10)时,已经给a赋值为10了,方法中再赋值报错 }
(2)final修饰非静态成员变量:
初始化方法:
①显式初始化:定义的时候直接赋值
②构造代码初始化:先定义,然后到匿名代码块中赋值
③构造器初始化:先定义,然后再所有显式构造器中另外赋值,初始化
注意:每个构造器中赋的值可以不同,因为创建对象,只执行一次,不会有第二次复制,但必须在每个构造器中都初始化。
set方法不可以用来给final修饰的变量赋值
class F { //第一种初始化方式:显式初始化 //private final int num = 10; //第二种初始化方式:构造代码块初始化 // private final int num; // { // num = 20; // } //第三种初始化方式:所有构造器中都对final成员进行初始化 private final int num; public F() { //必须给num初始化 this.num = 30; } public F(int num) { //必须给num初始化 this.num = num; } @Override public String toString() { return "F [num=" + num + "]"; } }
(3)final修饰静态成员变量
初始化方法:
①显式初始化:定义的时候直接赋值
②静态代码初始化:先定义,然后到静态代码块中赋值
class SF { //第一种初始化方式:显式初始化 //private final static int num = 10; //第二种初始化方式 private final static int num; static { num = 20; } //定义static方法,专门操作static数据成员 public static int getNum() { return num; } }
4、final修饰引用:
final修饰引用类型变量时,变量的引用地址值不能改变(栈区内的地址不能改,堆区对应的空间中存放的数据可以改)