面向对象(二)
1.this关键字
2.继承思想
3.方法覆盖
4.抽象方法和抽象类
5.Object中的常用方法
this关键字
成员变量与方法内部的变量重名时,会产生成员变量与局部变量的二义性这时候我们可以使用this
this 关键字用来表示当前对象本身,或当前类的一个实例
使用 this.变量名 的语法,此时访问的就是成员变量
作用域链:
作用域链:{}形成作用域,作用域可以嵌套,内层作用域可以访问外层作用域的变量
当在作用域中访问一个变量var,首先在自身作用域中找该变量var,如果自身作用域能找到,不继续向上一层找;
如果在本层没有找到,继续向上一层找,该层没有,继续向其上一层找,查找的过程形成一条链,这个链称为作用域链(scope chain)
public class Person {
private String name; //变量名被私有化
private int age;
public void rest(){
System.out.println(name+"正在咕噜咕噜");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age <0 ||age>150){
System.out.println("年龄不合法");
}else{
this.age = age;
}
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
setAge(age);
}
}
构造器和setter方法的选用
构造器和setter方法都可以给对象设置数据:
-
构造器,在创建对象的时候设置初始数据,只能初始化一次。
-
setter方法,创建对象后再设置初始数据,可以设置多次
继承思想
当多个类存在大量相同代码时,我们可以将其相同的特性与行为抽出,放到一个类中,让他们都继承这个类.可以解决多个类存在共同代码的问题
语法: 如果一个类需要继承另一个类,需要使用到extends
关键字
public class 子类名 extends 父类名{
}
概念:
- 被继承的类,称为父类
- 继承父类的类,称为子类
- 父类:存放多个子类共有的字段和方法
- 子类:存放自己特有的字段与方法
- Object类是Java语言的根类,任何类都是Object的子类,要么是直接子类,要么是间接子类
子类可以直接继承父类的非私有成员,但构造方法除外
java类继承的特性
- 单根型.只支持单继承,一个类只能有一个直接父类(一个孩子只能有一个爹),但支持多重继承
- 传递性.
C extends B ,B extends A
,C也具备A的特征和行为
访问修饰符判断
子类继承父类之后,可以拥有到父类的某一些成员(字段和方法),根据访问修饰符来判断:
在java中,存在4中修饰符,这4种修饰符用于控制java中 成员变量, 成员方法, 构造方法, 类, 接口等访问权限
修饰符 | 类内部 | 同包子类,同包其他类 | 不同包子类 | 不同包其他类 |
---|---|---|---|---|
private | √ | |||
默认 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
- private:私有的,只能本类可见默认:
- 没有关键字,包访问权限,同包可见
- protected:受保护的.①同包可见 ,②子类可见
- public:公共的,都可见
- 父类的构造器,子类也不能继承,因为构造器必须和当前的类名相同
- 访问权限大小:private < 默认< protected< public
继承在实战中的应用
1.两个类在现实中没有关系,但抽象的过程中发现他们有共同的特征和行为,提取公共成员形成父类
2.现实生活中,他们有继承关系,反应到现实中就是 is a关系 学生类 is a 人类
继承的操作
Person类(父类)
public class Person {
private String name;
private int age;
public void rest(){
System.out.println(name+"正在咕噜咕噜");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age <0 ||age>150){
System.out.println("年龄不合法");
}else{
this.age = age;
}
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
setAge(age);
}
}
Teacher类(子类)
public class Teacher extends Person {
//定义自身特有的字段和方法
private int level;
public void teach(String aClass){
System.out.println(getName() +"正在教:"+aClass);
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public Teacher(String name, int age, int level) {
setName(name);
setAge(age);
setLevel(level);
}
public Teacher() {
}
}
测试类
public class Test01Extends {
public static void main(String[] args) {
//创建对象
Teacher t1 = new Teacher();
//设置名字,从父类中调取的setter方法
t1.setName("小月");
//设置年龄
t1.setAge(18);
//子类teacher所自定义的字段
t1.setLevel = 100;
//调用父类中的方法
t1.rest();
t1.teach("英语");
}
}
方法覆盖
重写/覆盖(overwrite/overrides)
当子类从父类继承过来的方法不能满足自身需要时,子类可以选择重写/覆盖父类的同名方法
方法调用顺序
对象调用方法时,首先在子类查找,子类存在则执行子类,如果没有对应方法再去父类寻找,父类也没有就会报错
方法覆盖细节
- 方法重写建立在继承的基础上 所有private修饰的方法不能被重写
- 实例方法签名必须相同 (方法签名= 方法名 + 方法的参数列表)
- 子类方法的返回值类型是和父类方法的返回类型相同或者是其子类
- 子类方法中声明抛出的异常小于或等于父类方法声明抛出异常类型
- 子类方法的访问权限比父类方法访问权限更大或相等
重写与实现
重写与实现implements
(父类没有实现的方法,子类去实现了,实现是一种特殊的重写)
重写和实现的区别:
- 子类继承父类的方法时不能满足自身需求,子类可以选择重写父类的同名方法,这个同名的方法在父类中是实现过的,只不过不能满足子类需求,这个过程叫做重写(override/overwrite)
- 子类继承父类的抽象方法时,必须重写父类的抽象方法,这个过程称为实现(implement),因为父类中的方法是抽象的,没有方法体,父类重来就没有实现过这个方法
super关键字
当子类覆盖了覆盖的方法,而我们又想调用父类的方法时,我们可以使用super关键字
后续补充
抽象方法和抽象类
抽象方法
被abstract修饰,该方法没有方法体,要求子类必须覆盖该方法我们称为抽象方法
public abstract 返回类型 方法名(参数);
抽象类
使用abstract修饰的类,称为抽象类
public abstract class 类名{
}
一般的,抽象类以Abstract作为类名前缀
特点:
- 抽象类不能创建对象不能实例化),抽象类可以阻止实例化
- 抽象类中不一定只有抽象方法,可以有普通方法,但是有抽象方法的类,一定是抽象类
- 一个类继承抽象父类,必须实现抽象父类中的所有抽象方法,除非该类也是抽象类
Object类的常用方法
Object类是java中的根类,本身表示对象的意思
所有类都是Object类的子类,所有所有类的对象都可以调用Object类中的方法
这里讲Object中的equals方法与toString方法
boolean equals(Object obj)
:拿当前调用该方法的对象和参数obj做比较
String toString()
:表示把对象中的字段信息转换为字符串格式,打印对象时其实打印的就是对象的toString方法
equals
在Object类中的equals方法和“ == ”符号相同都是比较对象是否是同一个的存储地址
== 符号到底比较的是什么:
- 比较基本数据类型:比较两个值是否相等
- 比较对象数据类型:比较两个对象是否是同一块内存空间 每一次使用new关键字,都表示在堆中创建一块新的内存空间
每个类都应该覆盖equals方法去比较我们关心的数据,而不是内存地址,
实际开发过程中,如果两个不同地址的对象持有的数据相同(关键字段,例如学号),
我们称这两个对象业务上相等
重写toString方法
IDEA可以帮助我们重写,当然我们也可以自己重写
//字段
private String name;
private int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
重写equals方法
重写完后,比较的就是对象的数据业务是否相同了
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (age != person.age) return false;
return name != null ? name.equals(person.name) : person.name == null;
}