Java面向对象基础
面向对象特征二:继承性
一、继承
1、产生继承的原因:
为了减少多个相似类之间书写相同的属性和方法。
2、Java继承
继承是软件可重用性的一种表现,新类可以在不增加自身代码的情况下,通过从现有的类中继承其属性和方法,来充实自身内容,这种现象称之为继承。此时新类称为子类,现有的类称为父类。在Java中通过extends关键字实现继承关系。
(1)总结所有类的共同属性和方法,将这些属性和方法存储到基础类中;
(2)其他类通过关键字extends进行对这个基础类的继承,即获得基础类所拥有的属性和方法。
3、Java继承关系的特征
(1)子类继承父类,那么子类就自然而然拥有了父类约定的属性和方法。
(2)子类的对象也属于父类的对象。
(3)Java.lang.Object是所有类的父类。
(4)Java的继承是单继承。
4、子类无法继承父类的情况
(1)使用private关键字修饰的属性和方法;
(2)当子类和父类不在同一个包中,使用默认修饰的属性和方法;
(3)父类的构造方法,子类是无法继承。
(4)使用final关键字修饰的属性和方法。
5、创建子类对象的流程
(1)执行子类对象new关键字时,检测到子类继承了一个父类,那么首先会在堆内存中创建父类对象。
(2)创建完毕父类对象后,再创建子类对象,同时在子类中,使用super关键字存储父类对象的堆内存地址。
(3)子类构造方法开始执行,要求子类构造方法的第一行必须是调用父类的构造方法,意味着父类构造方法首先对父类对象进行初始化。
(4)父类对象初始化完毕后,才是子类对象构造方法其他代码的执行,也就是说子类才完成对象的初始化。
(5)至此,整个对象创建完毕。
二、super关键字
1、理解
父类的
2、作用范围
可以用来调用:属性、方法、构造器
3、super的使用
(1)我们可以在子类的方法或构造器中。通过使用“this.属性”或“this.方法”的方式,显式的调用父类中的属性或者方法。一般情况下,我们习惯省略"super."。
(2)特殊情况下,当子类和父类中定义了同名的属性时,我们想要在子类中调用父类声明的属性,则必须显式的使用“super.属性”的方式,表明调用的是父类中声明的属性。
(3)特殊情况下,当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用“super.方法”的方式,表明调用的父类中被重写的方法。
(4)super调用构造器:
- 我们可以在子类的构造方法中显式的使用“super(形参列表)”的方式,调用父类中声明的指定构造方法。
- “super(形参列表)”的使用,必须声明在子类构造方法的首行。
- 我们在类的狗在方法中,针对与“this(形参列表)”或“super(形参列表)”只能二选一,不能同时出现。
- 在构造器的首行,没有显式的声明“this(形参列表)”或“super(形参列表)”,则默认调用的时父类中空参的构造方法。
- 在类的多个构造方法中,至少有一个类的构造方法使用了“super(形参列表)”,调用父类中的构造器。
三、static关键字
1、理解
静态的
2、作用范围
可以用来修饰属性、方法、代码块、内部类;
(1)使用static关键字修饰属性:静态变量(或类属性)
- 属性:按是否使用static关键字修饰,又分为静态属性 vs 非静态属性(实例变量)。
(2)static修饰属性的其他说明: - 静态变量随着类的加载而加载。可以通过“类.静态变量”的方式进行调用。
- 静态变量的加载要早于对象的创建。
- 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。
(3)使用static修饰方法:静态方法 - 随着类的加载而加载,可以通过“类.静态方法”的方式进行调用。
- 静态方法中,只能调用静态的方法或者属性;非静态方法中,既可以调用非静态的方法或者属性,也可以调用静态的方法或者属性。
3、static注意点
(1)在静态的方法内,不能使用this关键字、super关键字。
(2)关于静态属性和静态方法的使用,大家都从生命周期的角度去理解。
(3)在开发中,当属性是可以被多个对象所共享的,不会随着对象的不同而不同,就可以使用static去修饰属性。
4、代码展示
public class StaticTest {
public static void main(String[] args) {
int a = 1;
Chinese c1 = new Chinese();
c1.name = "刘翔";
c1.age = 30;
c1.nation = "中国";
//c1.show();
Chinese c2 = new Chinese();
c2.name = "姚明";
c2.age = 31;
System.out.println(c2.nation);
System.out.println(Chinese.nation);
}
}
/**
* 中国人类
*
*/
class Chinese{
//属性
String name; //姓名
int age; //年龄
static String nation; //国家
public static void show() {
System.out.println("心情不好!");
}
}
四、方法重写(Override)
1、目的
方法重写的目的就是子类可以按照自己的业务流程对继承于父类的方法的方法体进行改造,来适应自己的需求。
2、理解
子类将继承于父类的方法,保持方法名和参数列表不变,改变方法体的现象,称之为继承。
3、方法重写的规则
(1)方法名相同;
(2)参数列表相同;
(3)返回值类型相同或者是父类返回值类型的子类;
(4)方法的访问权限不能严于父类,子类重写的可见性比父类大;
(5)父类的静态方法不能被子类覆盖为非静态方法,父类的非静态方法不能被子类覆盖为静态方法;
(6)子类重写父类的静态方法时,不能在方法体中使用;
(7)父类的私有方法不能被子类覆盖;
(8)不能抛出比父类更多的异常。
(9)为了强制检测子类方法是否重写了的父类方法,建议在子类重写的方法上增加注解@Override来进行强制检测。
4、方法重载(Overload)和方法重写(Override)的区别
五、Object类
在Java中,所有的类都是Object类的子类,Object类包含了所有类都具有的方法。
其中我们使用较多的有:
1、toString()
当我们调用System.out.println()在控制台输出一个对象时,本质上就会调用其toString()来进行显式其中字符串。
//如果希望通过System.out.println()在控制台输出对象时的结果更好看,对toString方法进行重写
public String toString() {
return "["+name+"]的身份证号:"+idCard;
}
Java在输出一个变量时,只会去虚拟机栈中进行查找该变量,如果时一个基本数据类型变量,那么变量值就直接存储在虚拟机栈中,就将这个值取出进行显示,而对象在虚拟机栈中所存储的是一个地址,于是就将这个地址取出进行显示。
2、equals()
在Java中,如果需要比较两个变量是否相等,既可以用“==”,也可以使用equals()。
(1)“==”是直接去虚拟机栈中查找这个变量的信息,然后进行比较,也就是说,对于基本数据类型来说,直接比较的是值是否相等,而引用数据类型,则比较的是两个对象的内存地址是否相等。
(2)equals()是提供给引用数据类型判断是否相等的方法,只不过Object类中的equals()底层仍然使用“==”,因此如果需要判断两个对象是否相等,那必须重写equals()。
@Override
public boolean equals(Object obj) {
//对于任何非null的值和null进行比较都必须是false
if(obj == null) {
return false;
}
//对于任何非null的引用值,x.equals(x)的结构必须是true
if(this == obj) {
return true;
}
//排除以上两种情况,那么需要首先确定obj是一个User类型的对象
//要想判断某个对象是否属于一个类型,则需要使用关键字instanceof
//如果这个对象属于该类型,那么instanceof返回的结果就是true,否则返回false
if(obj instanceof User) {
//那么说明obj这个对象就是User类型的对象
//此时obj就是User类型的对象,那么对obj进行类型强制转换
User user = (User) obj;
//那么此时this和obj就都是User类型,那么就可以进行比较
return this.idCard.equals(user.idCard);
}else {
//说明obj不是User类型的对象,那么和当前对象就没有可比性。
return false;
}
}
重写equals()原则:
- 自反性:对于任何非空的引用值,x.equals(x)的结果必须为true;
- 对称性:对于任何非空的引用值,x.equals(y)的结果是true,那么y.equals(x)的值也必须为true。
- 传递性:对于任何非空的引用值,x.equals(y)的结果是true,y.equals(z)的结果是true,那么x.equals(z)的结果也必须为true。
- 一致性:对于任何非空的引用值x,y,只要x.equals(y)的结果是true,在不改变x和y的情况下,无论比较多少次,x.equals(y)的结果都必须是true。
- 对于任何非null的值和null进行比较的结果都必须是false。