this关键字
用来区分访问成员变量和局部变量,this访问的是成员变量(暂时这么记)
public class Person {
private String name;
private int age;
public Person(){}
public Person(String name,int age){
//this.xxx:表示访问成员变量
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;
}
}
使用构造器还是setter方法
- 构造器: 在我们创建对象的同时对变量进行初始化,用这种方式对一个对象只能初始化一次,之后再初始化就需要使用setter,并且使用这种方法的前提是要知道有什么变量需要被初始化。
- setter方法: 创建对象之后的初始化,可以设置多次。
继承思想
当多个类具有相同的状态和功能的时候,那么我们就需要敲很多重复的代码,这时候就可以使用继承来解决这个问题了。
首先了解几个概念
- 被继承的类,称为父类,基类;
- 继承父类的类,称为子类,拓展类;
- 父类:存放多个子类共同的字段和方法
- 子类:存放自己特有的字段和方法
- 一个类可以有多个子类,但是只能有一个父类
- 可以存在多重继承,就是父类可以有父类
- Object类是java语言的根类,任何类都是Object的子类,要么是直接子类,要么是间接子类
继承的语法
public class 子类名 extends 父类名{}
子类可以继承到父类哪些成员
根据昨天学习的修饰符进行判断,只有protected和public修饰的能被子类继承,如果父类和子类在同一个包中,使用缺省访问修饰的成员,子类也可以继承。
- 如果父类中的成员使用private修饰,子类继承不到。private只能在本类中访问
- 父类的构造器,子类也不能继承,因为构造器必须和当前的类名相同
方法覆盖
当子类存在一个和父类一模一样的方法时,我们就称之为子类覆盖了父类的方法,也称之为重写。
访问流程:
通过对象调用方法时,现在子类中进行查找有没有对应的方法,如果有就执行,如果没有就去父类找,找到就执行,父类也没有就报错。
方法覆盖的细节:
- 实施覆盖的子类和父类中方法的签名必须相同
- 子类方法的返回值类型和父类方法的返回值类型相同
- 子类方法的访问权限比父类方法的访问权限更大或者相等
总而言之,实际写的时候我们把父类的方法直接复制一份到子类中进行修改就好了
super关键字:
当我们使用了方法覆盖,但是我们还想用父类的方法的时候,就可以用super关键字,他表示父类对象的意思。
语法:
super.fly()//可以翻译成调用父类对象的fly方法。
抽象方法和抽象类
作用:约束子类必须实现某个功能
- 抽象方法必须在抽象类或者接口中
- 抽象方法不能有方法体
- 要求子类必须覆盖该方法
语法:
使用abstract修饰
public abstract class 类名{
public abstract 返回值类型 方法名(参数);
}
抽象类
抽象类一般以Abstract作为类名前缀,一眼就能看出来是抽象类
特点:
- 抽象类不能创建对象
- 抽象类中可以拥有抽象方法和普通方法
- 抽象类要有子类才有意义,子类必须覆盖父类的抽象方法,否则子类也得作为抽象类,直到实现。
Object类和常用方法
Object本身表示对象的意思,是java中的根类,要么是一个类的直系父亲,要么就是一个类的间接父亲,因为所有类都是Object类的子类,所有类的对象都可以调用Object类中的方法。
equals
==
- 引用数据类型:比较的是地址
- 基本数据类型:比较的是值
equals
public boolean equals(Object obj) {
//在方法内部,this指向方法的调用者
return (this == obj);
}
//用法,在别的类中
public static void main(String[] args) {
//创建Person对象p1
Person p1 = new Person();
//创建Person对象p2
Person p2 = new Person();
//比较p1和p2的内存地址是否相同
boolean ret1 = p1 == p2;
boolean ret2 = p1.equals(p2);
System.out.println(ret1); //false
System.out.println(ret2); //false
}
可以看出,equals 和 == 引用数据类型的比较是完全一样的,但是基本数据类型不能使用equals进行比较。
但是在实际开发中我们通常是比较两个对象中的成员变量的值是否相等,来判断两个对象是否相同,可以在实际调用的方法中对epuals覆盖进行实现,所以建议在每个类中都对epuals进行覆盖去比较我们关心的数据,而不是内存地址。
toString()
表示把对象中的字段信息转换为字符串格式
打印对象时其实就是打印的对象的toString方法
Person p = new Person();
p.setName("will");
p.setAge(17);
System.out.println(p);
System.out.println(p.toString());
其中
System.out.println(p);
// 等价于
System.out.println(p.toString());
打印出来的就是地址:cn.wolfcode._04_object.Person@15db9742
cn.wolfcode._04_object.Person:类的全限定名(包.类)
默认情况下打印的是对象的地址,但是我们更关心对象中字段存储的数据。所以建议把每个类都覆盖toString返回我们关心的数据,如:
public class Person {
private String name;
private int 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 String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
此时打印出来的就是该对象的字段信息
Person [name=will, age=17]
println方法有去调用传递参数的toString方法