目录
继承的基本概念
继承的概念
继承的概念是:新类可以在不增加自身代码的情况下,通过从现有的类中继承其属性和方法,来充实自身内容,这种行为就称之为继承。
继承是软件可重用性的一种体现,新的类被称之为子类,被继承的类被称之为父类。继承的关系可以理解为一般和特殊的关系。
继承的基本作用是:使得代码可以重用,增加了代码的可扩充性。
继承的语法结构:
[访问修饰符] class <子类名称> extends <父类名称>{
}
1.extends是继承的关键字
定义一个Animal类
public class Animal {
}
创建一个Bird类和一个cat类来继承Animal类
public class Bird extends Animal{
}
public class Cat extends Animal{
}
继承的权限问题:
父类的类的访问修饰符为public时,子类可以在项目的任意位置继承父类
父类的类的访问修饰符为默认的空值时,子类只能在同一个包中继承该父类,否则将无法继承。
父类的成员的访问修饰符为public或者是protected时,子类可以在任意位置继承这些属性和方法
父类的成员的访问修饰符为默认值时,子类只能够在同一个包中继承这些属性和方法
父类的成员的访问修饰符为private时,子类将无法继承这些属性和方法。
子类无法继承父类的构造方法。
继承的应用
public class Animal {
//动物父类
private String name;
private int age;
private String color;
private String tail;
public Animal() {
System.out.println("生成了一只无参动物");
}
public Animal(String name, int age, String color, String tail) {
System.out.println("生成了一只有参动物");
this.name = name;
this.age = age;
this.color = color;
this.tail = tail;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void wolf(){
System.out.println("动物叫");
}
public void show(){
System.out.printf("name:%sage:%dcolor:%stail:%s",name,age,color,tail);
}
}
public class Cat extends Animal{
private String teech;
public Cat() {
}
public Cat(String teech) {
super();
this.teech = teech;
}
public Cat(String name, int age, String color, String tail, String teech) {
super(name, age, color, tail);
this.teech = teech;
}
public String getTeech() {
return teech;
}
public void setTeech(String teech) {
this.teech = teech;
}
}
public class Bird extends Animal{
private String wing;
public Bird() {
}
public Bird(String wing) {
this.wing = wing;
}
public Bird(String name, int age, String color, String tail, String wing) {
super(name, age, color, tail);
this.wing = wing;
}
public String getWing() {
return wing;
}
public void setWing(String wing) {
this.wing = wing;
}
}
public class Test {
public static void main(String[] args) {
Bird bird = new Bird("一对");
Bird bird2 = new Bird();
Cat cat = new Cat("锋利的");
Cat cat2 = new Cat("花花", 3, "橘色", "长", "锋利");
cat2.show();
}
}
结果为:
生成了一只无参动物
生成了一只无参动物
生成了一只无参动物
生成了一只有参动物
name:花花age:3color:橘色tail:长
super关键字
super可以调用父类的构造方法。
当子类的构造方法被调用时,会自动调用父类的无参构造方法,什么都不写等同于super();
也可以使用super(参数)来调用父类中有参的构造方法,此时无参的构造方法将不会被默认调用。
注意当使用super()去调用父类的构造方法时,应该写在子类构造方法的第一行
super关键字去引用被屏蔽的成员变量或成员方法,使用super访问父类的属性和方法
通过super.<属性名/方法名>来访问父类的相关属性与方法。
super关键字只能够出现在子类中,而不是其他位置。super关键字的调用也满足访问控制符规则,即父类的private属性/方法无法访问
Object类
Object类是所有类的间接或者直接父类,如果一个类没有使用extends关键字继承父类,那么这个类直接的继承了object类,否则,间接的继承了Object类
方法 | 说明 |
---|---|
toString() | 返回当前对象本身有关信息,返回字符串对象 |
equals() | 比较两个对象是否是同一个对象,若是,返回true |
clone() | 生成当前对象的一个副本,并返回 |
hashCode() | 返回该对象的哈希代码值 |
getClass() | 获取当前对象所属的类信息,返回Class对象 |
要注意,如果存在多级的继承关系,系统会一直从最上层的父类开始向下调用。
例如,上文创建了一个cat实例化对象,系统会先生成Object对象,Animal对象,Cat对象,并依照此种顺序执行他们的构造函数。
注意,如果一个类只定义了有参的构造函数,子类在继承父类时,如果没有声明使用父类的有参构造函数,系统会报错,因为系统会自动调用父类无参的构造函数,而父类的无参构造函数此时是不存在的。
方法重写
//在cat类中重写show方法
public void show(){
System.out.printf("name:%s teech%s "
,super.getName(),teech);
}
cat2.show();
name:花花 teech锋利
此时实例化的cat2.show();运行的是cat类重写之后的show方法。
在子类中根据需求对从父类继承的方法进行重新编写,这种方法称之为重写或者方法的覆盖
重写的要求
1、重写和被重写的方法要有相同的方法名
2、重写和被重写的方法要有相同的参数列表
3、重写方法的返回值必须和被重写方法的返回值类型相同或是其子类
4、重写方法不能缩小被重写方法的访问权限。
重载与重写的区别
重载发生在同一个类中,要求方法名相同,参数列表不同(参数类型||个数)与返回类型无关.
重写发生在不同的类中,作用于子类与父类之间,要求方法名相同,参数列表相同,返回值类型相同.
多态
1、多态的概念
多态是指能够呈现出多种不同的形式或者形态。在程序设计中多态意味着一个特定类型的变量可以引用不同类型的对象,并且能够自动的调用引用的对象的方法,也就是能根据作用到的不同对象类型,响应不同的操作。方法重写是实现多态的基础。
public class Test {
public static void main(String[] args) {
Animal animal2 ;
animal2 = new Bird();
Animal animal;
animal = new Cat();
bird.show()
cat.show();
//虽然定义的数据类型都是Animal
//也就是实例化的对象都是Animal但是调用的都是子类中重写的方法,这就是多态的一种体现
}
}
多态意味着在一次方法调用中根据包含的对象的实际类型(即实际的子类对象)来决定应该调用哪个方法,而不是由用来存储对象引用的变量类型来决定的。
当调用一个方法时,为了实现多态的操作,这个方法既是在父类中声明过的,也必须是在子类中重写的方法。
关于抽象类,抽象类使用abstract关键字修饰,抽象类实例化是没有任何意义的,因此抽象类创建的意义就是为了让子类继承,因此抽象类中
abstract修饰符不能和final关键字一起使用,private不能用来修饰abstract的相关抽象方法
抽象类的子类如果不是抽象类,那么子类必须重写所有抽象类中的抽象方法
2、向上转型
子类向父类转型称之为向上转型
向上转型的格式如下
<父类型><引用变量名>=new<子类型>()
上文使用到的
Animal animal = new Cat();
就是一个向上转型
有点类似于基本类型里面的转换问题
int a = 10;
double b =a;
因此向上转型时,将子类转换成父类满足以下规则:
将一个父类的引用指向一个字类的对象称为向上转型,系统会自动进行类型转换。
此时通过父类引用变量调用的方法是子类覆盖或继承了父类的方法,不是父类的方法。
此时通过父类引用变量无法调用子类特有的方法。
3、向下转型
向上转型时父类引用变量无法调用子类特有的方法,此时如果需要调用子类特有的方法,就可以通过把父类转换为子类来实现。
将一个指向子类对象的父类引用赋给一个子类引用,即将父类类型转换为子类类型,称之为向下转型,此时必须进行强制类型转换。
同样类似于基本类型的强制转换
double a = 10.0 ;
int b = double(a);
<子类型><引用变量名> = (<子类型>)<父类型的引用变量>
Cat cat = (cat)animal
此时cat可以进行cat类中的特有的方法
4、instanceof
在向下转型的过程中如果不是转换为真实子类类型,就会出现类型转换异常
Animal animal = new Cat();
animal.show();
Bird bird = (Bird)animal;//将animal转换成Bird会报错
此时可以使用instanceof运算符来进行类型判断
animal instanceof Bird
返回值是false
animal instanceof Cat
返回值是true
使用instanceof时,对象类型必须和instanceof 后面参数所指定的类有继承关系,否则会出现编译错误
例如:pet instanceof String 就会出现编译错误
instanceof 通常和强制类型转换结合使用
多态的应用
多态的优势为:
可替代性:多态对已存在的代码具有可替代性
可扩充性:多态对代码具有可扩充性,新增的子类不影响已存在类的多态性,继承性,以及其他特性的运行和操作性,实际上新加子类更容易获得多态功能。
接口性:多态是父类向子类提供了一个共同的接口,由子类具体实现。
灵活性:多态在应用中体现了灵活多样的操作提高了使用效率。
简化性:多态简化了应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为输出和重要。
1、使用父类作为方法的形参
class Host{
public void letCry(Animal animal){
animal.cry();
}
}
Host host = new Host();
Animal animal;
animal = new Cat();
host.letCry(animal);
animal = new Bird();
host.letCry(animal);
即将使用Animal父类作为参数类型,这样参数传递时,传递的参数为一个子类的动物对象
最终由这个对象来调用相应的方法
2.使用父类作为方法的返回值
class Host{
public Animal donateAnimal(String type){
Animal animal;
if(type == "cat"){
animal = new Cat();
}else{
animal = new Bird();
}
return animal;
}
}
Host host = new Host();
Animal animal ;
animal = host.donateAnimal("Cat")
animal.show();//猫的show方法