封装(encapsulation)
把一系列功能打包到一起,只提供使用这些功能的界面;
即将一系列相关事物的共同的属性和行为提取出来,放到一个类中,隐藏对象的属性和实现细节,仅对外提供公共的访问方式。
封装的关键就是绝不能让类中的方法直接访问其他类中的数据,程序仅通过对象的方法与对象的数据进行交互
继承(inheritance)
让类与类之间产生父子关系
子类继承父类后,子类拥有了父类的非私有成员(成员变量,成员方法)
public class ExtendDemo01 { public static void main(String[] args) { Child child=new Child(); child.setAge(22);//调用父类方法 //child.age; age属于父类的私有成员变量,子类无法继承 System.out.println(child.getAge()); } } class Child extends Parent{ } class Parent{ public Parent(){} private String name; private int age; public void setName(String name) { this.name = name; } public String getName() { return name; } public void setAge(int age) { this.age = age; } public int getAge() { return age; } }
一、继承关系中类成员的使用
继承关系中父类成员变量的使用:
如果子类与父类中定义了同名的成员变量,如何使用?
①子类中定义成员变量int price=20
②父类中定义成员变量int price=10
③子类成员方法中定义局部变量int price=5
④子类成员方法中分别输出三个price的值
public class ExtendDemo03 { public static void main(String[] args) { Apple apple=new Apple(); apple.showPrice();//有局部变量时,输出5 //没有局部变量,有子类成员变量时,输出10 //都没有时,输出20 } } class Apple extends Fruit{ //int price=10; public void showPrice(){ //int price=5; System.out.println(price); } } class Fruit{ int price=20; }
Java中使用变量的规则:遵循就近原则。局部位置有就使用,没有就去本类的成员位置找,有就使用,没有就去父类的成员位置找,有就使用,没有就报错。
System.out.println(this.price);//本类中的成员变量
System.out.println(super.price);//父类中的成员变量
super表示当前对象父类的引用
二、继承关系中子父类成员方法的使用
子父类中定义了同名的成员方法,如何使用?
public class ExtendDemo04 { public static void main(String[] args) { NineYin nineYin=new NineYin(); nineYin.stroke(); nineYin.internalStrength(); } } class NineYin extends Martial{ public void internalStrength(){//在父类的基础上作拓展 super.internalStrength();//调用父类成员方法 System.out.println("以柔克刚");//重写了父类的成员方法 } public void stroke() {//直接覆盖了父类的方法 System.out.println("九阴白骨爪"); } } class Martial{//武功类 //练习内功 public void internalStrength(){ System.out.println("练习内功"); } //练习招式 public void stroke(){ System.out.println("练习招式"); } }
访问父类方法的方式:super.父类方法名
三、继承关系中子父类构造方法的使用
public class ExtendDemo05 { public static void main(String[] args) { Worker worker=new Worker(); } } class Worker extends Person{ public Worker(){ System.out.println("worker"); } } class Person{ public Person(){ System.out.println("person"); } } 输出结果为:person worker
创建子类对象时,会优先调用父类的构造方法
子类构造方法的第一行,隐含语句super(),用于调用父类默认无参构造
2、父类中不存在默认无参构造方法怎么办?
子类创建对象时,必须先初始化该对象的父类内容,若父类中不存在默认无参构造,须手动调用父类有参数的构造方法。
public class ExtendDemo06 { public static void main(String[] args) { Worker1 worker=new Worker1(); } } class Worker1 extends Person1{ public Worker1(){ super("wangyingjing");//没有这一句时,系统会报错,提示父类没有默认无参构造 System.out.println("worker"); } } class Person1{ public Person1(String name){ System.out.println("person"+name); } }
四、Java中继承的特点
-
单继承
Java中只支持类的单继承,但是支持多层继承
Java支持接口的多继承,语法:接口A extends 接口B,接口C,接口D...
-
父类私有成员不能继承
-
构造方法不能继承,构造方法是用于初始化本类对象,继承没有意义。但在创建子类对象时要调用父类的构造方法进行初始化。
-
子类只有一个父类
多态(polymorphism)
多种状态,同一对象在不同情况下表现出不同的状态或行为
1、Java中实现多态的步骤:
-
要有继承(或实现(类和接口之间的关系))关系
-
-
父类引用指向子类对象
public class DuoTaiDemo01 { public static void main(String[] args) { //演示多态 /*实现多态:有继承或实现关系 有方法重写 要有父类引用指向子类对象 */ Animal1 animal1=new Dog1(); //要有父类引用指向子类对象 //编译看左,运行看右 //多态中调用成员是看左边的类中有没有这个成员,运行时具体看用的是右边类中的该成员 animal1.setName("花花"); animal1.eat();//注释掉Animal1中的eat方法,这里会报错 } } class Dog1 extends Animal1{ @Override public void eat(){ System.out.println(getName()+"是一只狗,它正在吃东西"); } } class Animal1{ public Animal1(){} public Animal1(String name){ this.name=name; } private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } public void eat(){ System.out.println(name+"正在吃东西"); } }
2、多态的效果演示
需求:父类型变量作为参数时,可以接收任意子类对象
分析:- 定义方法,参数类型为父类型Animal:showAnimal(Animal animal)
-分别创建Dog类和Mouse类的对象
-调用showAnimal方法演示效果
public class DuoTaiDemo02 { public static void main(String[] args) { //用来测试Dog类和Mouse类 //测试Dog类 Dog2 dog2=new Dog2(); dog2.setName("花花"); showAnimal2(dog2); //测试老鼠类 Mouse mouse=new Mouse(); mouse.setName("小小"); showAnimal2(mouse); } /* 传统测试方法 public static void showAnimal2(Dog2 dog2){ dog2.eat(); } public static void showAnimal2(Mouse mouse){ mouse.eat(); } */ //多态 //多态的使用场景:父类型可以作为形参的数据类型,这样可以接收其任意的子类对象 public static void showAnimal2(Animal2 animal2){ animal2.eat();}} class Dog2 extends Animal2{ @Override public void eat(){ System.out.println(getName()+"正在吃东西"); } } class Mouse extends Animal2{ public void eat(){ System.out.println(getName()+"在吃东西"); } } class Animal2{ private String name; public Animal2(){ } public Animal2(String name){ this.name=name; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void eat(){ System.out.println(name+"吃东西"); } }
3、多态关系中成员变量的使用
多态关系中成员变量的使用:
子父类中定义了同名的成员变量,如何调用?
package com.wang.duixiang; public class DuoTaiDemo03 { public static void main(String[] args) { Animal3 animal3=new Dog3(); System.out.println(animal3.name); Dog3 dog3=new Dog3(); System.out.println(dog3.name); } } class Dog3 extends Animal3{ String name="Dog3"; } class Animal3{ String name="Animal3"; } 输出结果为:Animal3 Dog3
多态关系中,成员变量不能重写。并且使用成员变量时,编译看左,运行看左
4、多态的好处和弊端
①可维护性 基于继承关系,只需要维护父类代码,提高了代码的复用性,大大降低了维护程序的工作量
②可拓展性 把不同的子类对象都当作父类看待,屏蔽了不同子类对象间的差异,做出通用的代码,以适应不同的 需求,实现向后兼容
弊端:不能使用子类特有成员
当需要使用子类特有功能时,需要进行类型转换:向上转型:Animal animal=new Dog()
向下转型:Dog dog=(Dog)animal
注意:只能在继承层次内进行转换,否则会出现(ClassCastException类型转换异常)
将父类对象转换为子类之前,使用instanced进行检查
public class DuoTaiDemo04 { public static void main(String[] args) { //通过多态创建对象 Animal4 animal4=new Dog4(); animal4.eat(); //调用子类独有的方法 if(animal4 instanceof Dog4){//判断animal4是否是Dog4类的对象 Dog4 dog4=(Dog4)animal4; dog4.watch();} } } class Dog4 extends Animal4{ @Override public void eat() { System.out.println("狗吃骨头"); } //狗类中独有的方法,父类中没有 public void watch(){ System.out.println("狗可以看家"); } } class Animal4{ public void eat(){ System.out.println("吃东西"); } }