第五章面向对象编程(中)
5.1 面向对象特征之二:继承性
一、继承性的好处:
① 减少了代码的冗余,提高了代码的复用性
② 便于功能的拓展
③ 为之后多态性的使用,提供了前提
二、继承性的格式:class A extends B{}
A:子类,派生类,subclass
B:父类1、超类、基类,superclass
2.1 体现:一旦子类A继承父类B以后,子类A中就获得了父类B中声明的结构:属性、方法
特别的,父类中声明为private的属性或者方法,子类继承父类之后,仍然认为获取了父类中私有的结构。
只是因为封装性的影响,使得子类不能直接调用父类的结构
2.2 子类继承父类之后,还可以声明自己特有的属性和方法,实现功能的拓展。
三、java中关于继承的规定
- 一个类可以被多个子类继承。
- java中的单继承性:一个类只能有一个父类
- 子父类是相对的概念
- 子类直接继承的父类,称为直接父类,间接继承的父类称为:间接父类
- 子类继承父类以后,就直接父类以及所有间接父类中声明的属性和方法
四、说明
- 如果我们没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类
- 所有的java类(除java.lang.Object类)都直接或者间接的继承于java.lang.Object类
5.2 方法的重写
定义
在子类中可以根据需要对父类中继承来的方法进行改造,也称为方法的重置、覆盖。
应用
重写以后,当创建子类对象以后,通过子类对象调用子父类的同名同参数的方法时,实际执行的是子类重写父类的方法。
重写的规则
约定俗成:子类中叫重写的方法,父类中叫被重写的方法
① 子类重写的方法的方法名和形参列表与父类中被重写的得方法的方法名和形参列表相同
② 子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符
> 特殊情况:子类不能重写父类中生命为private权限的方法
③ 返回值类型:
> 父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
> 父类被重写的方法的返回值类型是A类型,则子类的重写的方法的返回值类型可以是A类型或者A类的子类。
> 父类被重写的方法的返回值类型是基本数据类型,则子类的重写的方法的返回值类型必须是相同的基本数据类型
④ 子类重写的方法抛出的异常类型不大于父类中叫被重写的方法抛出的异常类型
注意
子类和父类中同名同参数的方法要么都声明为非static(考虑重写),要么都声明为static的(不是重写)。
面试题:区分方法的重载与重写
5.3四种访问权限修饰符
5.4 关键字:super
- super理解为:父类的
- super可以用来调用:属性、方法、构造器
- super的使用:属性和方法
① 我们可以在子类的方法或者构造器中·,通常使用·“super.属性”或者“super.方法”的方式,显式的调用父类中声明的属性或方法,但是,通常情况下,我们习惯省略“super.”
② 特殊情况:当子类和父类定义了同名的属性时,我们想要调用父类的属性时,则需要显式的使用“super.属性”的方式,表明调用的是父类中声明的属性 - super的使用:构造器
① 我们可以在子类的构造器中显式的使用“super(形参列表)”的方式,调用父类中声明的指定的构造器
② “super(形参列表)”的使用,必须声明在子类构造器的首行
③ 我们在类的构造器中,针对“this(形参列表)”或者“super(形参列表)”只能二选一,不能同时出现。
④ 在构造器的首行,没有显式的声明“this(形参列表)”或者“super(形参列表)”,则默认调用的是父类中空参的构造器:super()
⑤ 在类的多个构造器中,至少有一个类的构造器中使用了“super(形参列表)”,调用父类的构造器
5.5 子类对象实例化过程
-
从结果上看:(继承性)
子类继承父类以后,就获取了父类声明的属性或者方法。
创建子类的对象,在堆空间中·,就会加载所有父类中声明的属性 -
从过程来看:
当我们通过子类的构造器创建对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,…直到调用了java.lang.Object类中空参的构造器为止
5.6 面向对象特征之三:多态性
1 理解多态性:可以理解为一个事物的多种形态。
2 何为多态性:
对象的多态性:父类的引用指向子类的对象
当调用子父类同名同参数的方法时,实际执行的的是子类重写父类的方法–虚拟方法调用
3 多态性的使用:虚拟方法调用
有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但是在运行期,我们实际执行的是子类重写父类得方法。
总结:编译看左边,运行看右边
4 多态性的使用前提:
① 类的继承关系
② 方法的重写
5 对象的多态性,只适用于方法,不适用于属性
多态是运行时行为
package com.atguigu.java3;
//多态性的使用举例一
public class AnimalTest {
public static void main(String[] args) {
AnimalTest test = new AnimalTest();
test.func(new Dog());
}
public void func(Animal animal){
animal.eat();
animal.shout();
}
}
class Animal{
public void eat(){
System.out.println("动物进食");
}
public void shout(){
System.out.println("叫声");
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗粮");
}
@Override
public void shout() {
System.out.println("汪汪");
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫粮");
}
@Override
public void shout() {
System.out.println("喵喵");
}
}
向下转型的使用
使用强转时,可能会出现ClassCastException的异常。
package com.atguigu.java;
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Man();
p1.eat();
PersonTest test = new PersonTest();
System.out.println("*************************");
//不能调用子类所特有的方法,编译时 p1是Person类型
//p1.earnMoney();
//有了对象的多态性以后,内存中实际加载了子类特有的属性和方法的,但是由于变量变量声明为父类类型
//导致在编译时,只能调用父类中声明的属性和方法
//如何才能调用子类特有的属性和方法
//向下转型
Man m1 = (Man) p1;
m1.earnMoney();
}
}
instanceof的使用
a instanceof A:判断对象a是否是A的实例
如果是返回true,不是返回false
使用情景:为了避免在向下转型时出现异常,在向下转型之前,先进性instanceof的判断。
类B是类A的父类,如果a instanceof A返回true,则a instanceof B 也返回true。
多态的面试题
输出结果:sub_1
5. Object类的使用
Object类是所有java类的父类
java.lang.Object类
Object类只声明了一个空参的构造器
Object类中的功能(属性,方法)
属性:无
方法:equals()/ toString() / getClass() / hashCode()…
面试题: ==与equals() 区别
一、 回顾= = 的使用:
==:运算符
- 可以使用在基本数据类型变量和引用数据类型变量中
- 如果比较的是基本数据类型变量,比较两个变量保存的数据是否相等,(不一定类型要相同)
- 如果比较的是引用数据类型,则比较的是地址值是否相同。
int i = 10;
int j = 10;
double d = 10.0;
System.out.println(i == j);
System.out.println(i == d);//true
char c = 10;
System.out.println(i == c);//true
char c1 = 'A';
char c2 = 65;
System.out.println(c2 == c1);//true
二、equals()方法的使用
是一个方法,而非运算符。
只能适用于引用数据类型
Object类中equals()的定义:
public boolean equals(Object obj) {
return (this == obj);
}
说明:Object类中定义的equals()和== 的作用是相同的,比较两个对象的地址值是否相同。
像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后、比较的不是两个引用的地址值是否相同,二是比较两个对象的“实体内容”是否相同。
public class Customer {
String name;
int age;
public Customer(String name,int age){
this.age = age;
this.name = name;
}
}
Customer cust1 = new Customer("Tom",21);
Customer cust2 = new Customer("Tom",21);
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println("********************");
System.out.println(cust1.equals(cust2));//false
System.out.println(str1.equals(str2));//true
toString()的使用
在Object类中的定义
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
像String、Date、File、包装类等都重写了Object类中的toString()方法。
Customer cust1 = new Customer("Tom",21);
System.out.println(cust1.toString());//com.atguigu.java1.Customer@1b6d3586
System.out.println(cust1);//com.atguigu.java1.Customer@1b6d3586
String str = new String("hello");
System.out.println(str.toString());//hello
单元测试
包装类的使用
基本类型、包装类、String类间的转换
包装类的使用
java提供了8种基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征。
①基本数据类型转成包装类
int num1 = 10;
Integer in1 = new Integer(num1);
System.out.println(in1);
Integer in2 = new Integer("123");
System.out.println(in2.toString());
Float f1 = new Float(12.3);
System.out.println(f1);
Boolean b1 = new Boolean("123");
Boolean b2 = new Boolean("TrUe");
System.out.println(b2);//true
②包装类转变成基本数据类型
Integer in1 = new Integer(12);
int i1 = in1.intValue();
System.out.println(i1);//12
Float f1 = new Float(12.3);
float f2 = f1.floatValue();
System.out.println(f2);//12.3
③自动装箱与自动拆箱
int num1 = 10;
Integer in1 = num1;
System.out.println(in1.toString());//10
int num3 = in1;
System.out.println(num3);//10
④基本数据类型、包装类转成String类型
int num1 = 10;
//连接运算
String str1 = num1 + "";
//调用String的valueOf()
float f1 = 12.3f;
String str2 = String.valueOf(f1);
System.out.println(str1);//10
System.out.println(str2);//12.3
⑤String转换成基本数据类型
String str1 = "123";
int num1 = Integer.parseInt(str1);
System.out.println(num1 + 1);//124
String str2 = "true1";
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1);//flase
面试题