文章目录
1、面向对象的特征之二: 继承性
1.1、继承性的概述
为什么要有继承性?
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
继承性的好处
- 减少了代码的冗余,提高了代码的复用性
- 便于功能的拓展
- 为多态性提供了前提
1.2、继承性的格式与规定
继承性的格式
class A extends B
A : 子类、派生类、 subclass
B : 父类、超类、基类、superclass
- 子类(A)继承了父类(B),子类就获得了父类声明的所有属性和方法(private修饰的属性和方法除外,因为受到封装性的影响,使得子类不能直接调用父类的结构)(继承性的体现)
- 子类继承父类以后,还可以声明自己特有的属性或方法,实现功能的拓展。
继承性的规定
- 一个类可以被多个子类继承
- 一个类只能有一个父类(单继承性)
- 子类继承父类后,就获取了直接父类以及所有间接父类中声明的属性和方法。
- 父类、子类是相对的(直接父类、间接父类)
- 如果我们没有显式的声明一个类的父类的话,则此类继承于 java.lang.Object 类
- 所有Java类直接或间接继承java.lang.object类(意味着,所有的 java 类具有 java.lang.Object 类声明的功能)
1.3、方法的重写
- 创建子类对象以后,通过子类对象调用与父类同名同参的方法时,子类覆盖父类的方法(子类的权限修饰符范围不小于父类的)
重写的规定:
- 重写无法覆盖属性
- 只能覆盖同名同参的方法
- 子类不能重写private修饰的方法,计算机会自动任务是两个不同的方法
- 子类抛出的异常类型不大于父类
- 关于返回值类型
父类 | 子类 |
---|---|
void | void |
基本数据类型 | 相同的基本数据类型 |
引用数据类型(A) | A类或A的子类 |
重写与重载的区别!!!
- 方法的重写和重载是Java多态性的不同表现。
- 重写是子父类之间多态性的一种表现,重载是一个类中多态性的一种表现。
- 如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载
- 如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写,当子类对象调用此方法时,那么父类中同名同参的方法相当于被“屏蔽”了
2、super关键字
- super(父类的)
- super可以用来调用:属性、方法、构造器
super的使用
- 我们可以在子类的方法或构造器中,通过 " super.属性 “或” super.方法 “的方式,显式的调用父类中声明的属性或方法。但是,通常情况下,我们习惯去省略这个"super.”
- 当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用"super.属性"的方式,表明调用的是父类中声明的属性。
- 当子类重写了父类中的方法后,我们想在子类的方法中调用父类中被重写的方法时,必须显式的使用"super.方法"的方式,表明调用的是父类中被重写的方法。
- super调用构造器
- 我们可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器
- "super(形参列表)"的使用,必须声明在子类构造器的首行!
- 我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)"只能二选一,不能同时出现。
- 在类的多个构造器中,至少有一个类的构造器使用了"super(形参列表)",调用父类中的构造器。
- 在构造器的首行,既没有显式的声明"this(形参列表)“或"super(形参列表)”,则默认的调用的是父类 中的空参构造器。super()
3、面向对象的特征之三: 多态性
多态性的理解:可以理解成一种事物的多种态性
对象的多态性:子类的对象赋给父类的引用(父类的引用指向子类的对象)
3.1、多态的使用
- 在编译期,只能调用父类声明的方法
- 在执行期,执行子类重写父类的方法(运行时行为)
- 简称:编译时,看左边;运行时,看右边。
- 若编译时类型和运行时类型不一致,就出现了对象的多态性(Polymorphism)
- 使用前提:
- 1、类的继承关系
- 2、方法的重写
- 对象的多态性:只适用于方法,不适用于属性
- 有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类的属性和方法不能调用。
- 动态绑定:编译时调用父类方法,运行时执行重写子类方法的过程
- 虚拟方法:多态情况下,父类的方法称为虚拟方法
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.eat();
Man man = new Man();
man.eat();
man.age = 25;
man.earnMoney();
// 对象的多态性,父类的引用指向子类的对象
Person p2 = new Man();
// 多态的使用:当调用子父类同名同参数方法时,实际调用的是子类重写父类的方法---虚拟方法调用
p2.eat();
p2.walk();
// 不能调用子类(Man类)所特有的方法、属性,编译时,p2是Person类型,而earnMoney()属于Man类
// p2.earnMoney();
3.2、instanceof关键字
- a instanceof A:判断对象a是否是类A的实例。如果,返回true,如果不是,返回false;
- 使用情境:
- 为了避免在向下转型时出现ClassCastException异常,我们在进行向下转型之前,先进行
instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。
- 为了避免在向下转型时出现ClassCastException异常,我们在进行向下转型之前,先进行
- 当A是B的子类时,如果 a instanceof A == true ,那么 a instanceof B == true
// 如何才能调用子类所特有的属性和方法?
// 使用强制类型转换符,也可称为:向下转型
Man m1 = (Man) p2;
m1.earnMoney();
m1.isSmoking = true;
// 使用强转时,可能出现ClassCastException异常
// Woman w1 = (Woman)p2;
// w1.goShopping();
//使用instanceof关键字避免异常的出现
if( p2 instanceof woman)
woman w1=(woman)p2
//不过显然这个是无法转换的,因为虽然man类与woman类都继承与person类,但是这两个类之间是并列关系无法实现类型转换
3.3、多态是运行时行为的证明
证明如下:
public class test {
public static aniamls choose(int key){
switch (key){
case 1:
return new lion();
case 2:
return new monkey();
case 3:
return new cattle();
}
return new aniamls();
}
public static void main(String[] args){
int key=(int)( Math.random()*3 +1);
System.out.println(key);
choose(key).eat();
}
}
class aniamls{
public void eat(){
System.out.println("动物吃东西");
}
}
class lion extends aniamls{
public void eat(){
System.out.println("狮子吃肉");
}
}
class monkey extends aniamls{
public void eat(){
System.out.println("猴子吃香蕉");
}
}
class cattle extends aniamls{
public void eat(){
System.out.println("牛吃草");
}
}
- 你无法在编译期间就知道程序会调用哪一个对象,只有在运行期间才能知道。
4、Object类
- 全名 java.lang.Object 类
- Object类是所有Java类的根父类
- 如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
- Object类中的功能(属性、方法)就具有通用性。
- Object中无属性
- Object类中常用方法
5、 “ == ” 与 equals ()的对比
- ==
- 可以使用在基本数据类型变量和引用数据类型变量中
- 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。
- 如果比较的是引用数据类型变量:比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体
- == 使用时,必须保证符号左右两边的变量类型一致。
- equals()
- 是一个方法,而非运算符
- 只能适用于引用数据类型。
- equals()的源码
public boolean equals(Object obj){
return (this == obj);
}
//由此可以知道,equals()与 == 作用是相同的
//一般情况下,如果我们需要调用equals() 都会在目标类中重写它,使其充当比较对象实体的功能
//重写的方法
public boolean equals(Object o) {
if (this == o)
return true;
if (o instanceof Person){
Person p1=(Person)o;
if(this.name == p1.name) //比较Person类中name属性的实体
return true;
}else
return false;
}
//在编译中,我们一般直接调用idea写好的结构(快捷键 Alt + Ins)
6、包装类
6.1、包装类的使用
基本数据类型 | 对应包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
douuble | Double |
float | Float |
boolean | Boolean |
char | Character |
6.2、包装类与基本数据类型的转换
package test1;
import org.testng.annotations.Test;
public class WrapperTest {
@Test
public void test1() {
//基本数据类型 ——》 包装类
//方式1:调用包装类构造器
Integer t1 = new Integer(15);
System.out.println(t1);
String t2 = new String("ABC");
System.out.println(t2);
//特殊的: 对于纯数字的字符串 也可以调用 整型 包装类的构造器
Integer t3 = new Integer("123");
System.out.println(t3);
Double t4 = new Double("123.456");
System.out.println(t4);
//方式2:自动装箱
Integer t5 = 100;
System.out.println(t5);
Double t6 = 123.4;
System.out.println(t6);
}
@Test
public void test2() {
//包装类-》基本数据类型
//方式1:调用 XXXValue()
Integer t1 = new Integer(15);
int t2 = t1.intValue();
System.out.println(t2);
//使用了匿名对象
float t3 = new Float(454.58).floatValue();
System.out.println(t3);
//方式2:自动拆箱
int t4 = new Integer(20);
System.out.println(t4);
}
@Test
public void test3() {
//基本数据包类型、包装类 -》 String类型
//方式1: + “ ”
String t1=15+"";
System.out.println(t1);
//方式2: 调用String类中的valueOf(XXX)方法
String t2=String.valueOf('a');
System.out.println(t2);
//方式3: 调用包装类的toString()方法
String t3= new Integer(11).toString();
System.out.println(t3);
}
@Test
public void test4(){
//String类型 -》 基本数据类型、包装类
//方式1:调用各个包装类的 parseXXX()方法
Integer t1=Integer.parseInt("123");
System.out.println(t1);
//方式2:调用构造器
Integer t2=new Integer("789");
System.out.println(t2);
}
}