一、面向对象三大特征之继承extends
1.继承:就是将子类共有的特性提取到父类中,让子类可以继承父类的的这种特性,产生的这种关系就是继承关系extends
2.继承的好处:
1)提高代码的复用性
2)提高了代码的维护性
3)继承是多态的前提条件
3.继承的特点:
1)Java语言中只支持单继承,不支持多继承
2)Java中不能多继承,但可以多级继承。如:子类继承父类,父类继承爷爷类,子类也就间接的继承了爷爷类
4.注意事项:
1)子类继承父类,继承父类的所有非私有化成员
本身私有的成员变量/成员方法只能在本类中访问,外界不能访问的!,但是间接通过公共的访问方法来访问,setXxx()方法和getXxx()方法
2)子类继承父类,不继承父类的构造方法,但可以通过super关键字来访问父类的构造方法
3)因为继承提高了代码的耦合性,所以不要为了使用部分功能而去使用继承
5)继承中的成员关系:
1)子类继承父类,如果子类中的成员变量名称和父类的成员变量名称不一致的情况: 分别访问 既可
2)如果子类中的成员变量名称和父类的成员变量名称一致的情况:先在自己的局部位置找,找到就使用,找不到就去子类的成员位置找,还没有,就去父类的成员位置找,再找不打就报错, 遵循一个:"就近原则"
class Fu{
//成员变量
public int num = 100 ;
public void method() {
int num = 20 ;
System.out.println(num);
}
}
class Zi extends Fu{
//成员变量
//public int num2 = 200 ;
//public int num = 50 ;
//子类的成员方法
public void show() {
System.out.println(num);
}
}
//测试类
public class Demo{
public static void main(String[] args) {
Zi z = new Zi() ;
//子类成员变量名称和父类成员变量不一致的情况:
System.out.println(z.num);
System.out.println(z.num2);
//子类成员变量名称和父类成员变量一致的情况:
z.show();
}
}
6.关于继承中构造方法的关系:
1)子类是不能继承父类的构造方法的,但是通过super()来访问父类的构造方法
2)在继承中,子类中所有的构造方法都默认访问父类的无参构造方法;
相当于子类的所有构造方法的第一句话:隐藏了super();
问题: 为什么,创建子类对象的时候,先执行父类的无参构造方法?
因为可能要用到父类中的数据,所以要先让父类中的数据进行初始化(构造方法),
父类初始化完毕了,然后才执行子类的构造方法(子类数据初始化)---->分层初始化!
super():如果在子类的构造方法显示给出了,必须写在第一句,否则可能出现父类初始化多次!(可以省略不写.)
class Fu2{
public Fu2() {
System.out.println("这是父类的无参构造方法");
}
public Fu2(String name) {
System.out.println("这是父类的有参构造方法");
}
}
//定义一个子类
class Zi2 extends Fu2{
public Zi2() {
super("随便给") ;//里面不给访问的父类无参,随便给访问的父类有参,匹配父类的形参类型就行
System.out.println("这是子类的无参构造方法");
}
public Zi2(String name) {
//this();
super("随便给");
System.out.println("这是子类的有参构造方法");
}
}
//测试类
public class ExtendsDemo2 {
public static void main(String[] args) {
//创建子类对象
Zi2 z = new Zi2() ;
}
}
7.经典的猫狗案例(继承版)
public class Animal{
//属性私有化
private String name ;//姓名
private int age ;//年龄
private String color ;//颜色
//无参构造方法:alt+shift+s-->c
public Animal() {
super();
}
//有参构造方法:all+shift+s--->o
public Animal(String name, int age, String color) { //"tom",3,"黄色"
super();
this.name = name; //将具体的局部变量值赋值给成员变量了
this.age = age;
this.color = color;
}
//公共访问方法:alt+shift+s--->r
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
//其他成员方法
public void eat() {
System.out.println("动物了都需要吃饭...");
}
public void sleep() {
System.out.println("动物困了都需要休息...");
}
}
//猫类
public class Cat extends Animal {
//alt+shift+s---c:全部生成!
public Cat() {
super();
}
public Cat(String name, int age, String color) {
super(name, age, color); //super(xxx)访问父类的有参构造
//super("tom",3,"黄色") ;
}
//猫的特有功能
public void catchMouse() {
System.out.println("猫抓老鼠...");
}
}
//狗类
public class Dog extends Animal {
public Dog() {
super();
// TODO Auto-generated constructor stub
}
public Dog(String name, int age, String color) {
super(name, age, color);
}
//特有功能
public void lookDoor() {
System.out.println("看门...");
}
}
二、面向对象三大特征之多态
1.多态:一个事物在不同时刻的体现。如:猫可以是猫,也可以看作动物; 水可以是固态,液态,气态
2.前提条件:
1)实现继承
2)方法重写
3)父类对象引用指向子类 父类名 对象名 = new 子类名() ; //称为"向上转型
3.优点:
1)提高了代码的复用性(由继承来保证)
2) 提高了代码的扩展性(由多态的来保证)
4.猫狗案例(多态版)
多态的弊端:不能访问子类的特有功能,两种方法解决:
1)创建具体的子类对象(更耗费内存,因为重新开辟了堆内存空间)
2)向下转型 Zi z =(Zi)f;前提条件有多态: Fu f =new Zi();
class Animal{
public void eat() {
System.out.println("动物需要吃饭");
}
public void sleep() {
System.out.println("动物需要休息");
}
}
//定义一个子类
class Dog extends Animal{
public void eat() {
System.out.println("狗吃狗粮");
}
public void sleep() {
System.out.println("狗卧着睡觉");
}
//特有功能
public void lookDoor() {
System.out.println("狗可以看门...");
}
}
//测试类
public class DuoTaiDemo4 {
public static void main(String[] args) {
//多态的格式:父类引用指向子类对象(向上转型)
Animal3 a = new Dog3() ;
a.eat();
a.sleep();
//a.lookDoor() ;
//方案1)创建子类的具体对象来访问子类的特有功能!
/*Dog3 d = new Dog3() ;
d.lookDoor();*/
//向下转型:
Dog d = (Dog)a;
d.lookDoor();
}
}
5.多态中的成员访问问题
Fu f = new Zi();
1)成员变量: 编译看左边,运行看左边!
2)成员方法:编译看左边,运行看右边!(方法重写)
3)静态的成员方法: 编译看左,运行看左!(静态的算不上方法重写,跟类直接相关,随着类的加载而加载!)
4)构造方法:存在继承关系(还是分层初始化) 先让父类初始化,然后在是子类初始化!
class Fu{
public int num = 100 ;
public void show() {
System.out.println("show Fu");
}
public static void function() {
System.out.println("function Fu");
}
}
//子类
class Zi extends Fu{
public int num2 = 200 ;
public int num = 50 ;
public void show() {
System.out.println("show Zi");
}
public static void function() {
System.out.println("function Zi");
}
}
//测试类
public class DuoTaiDemo {
public static void main(String[] args) {
Fu f = new Zi() ;
System.out.println(f.num); //100
f.show(); //show Zi
f.function(); //function Fu
}
}
6.一道多态综合练习题
//看程序,写结果
class A {
public void show() {
show2();
}
public void show2() {
System.out.println("我");
}
}
class B extends A {
/*
* public void show() {
show2();
}
* */
public void show2() {
System.out.println("爱"); //爱
}
}
class C extends B {
public void show() {
super.show();
}
public void show2() {
System.out.println("你");//你
}
}
public class Test3 {
public static void main(String[] args) {
A a = new B();
a.show();
B b = new C();
b.show();
//向下转型
C c =(C)b;
c.show();
}
}
//结果是: 爱 你 你
三、抽象类(abstract)
1.概念:定义抽象类的原因就是没有具体的实例化对象,更加贴近现实,如:现实中没有动物这个东西,它是抽象的
故概念是在一个类中,如果该类中存在一个功能,仅仅方法声明,没有方法体(抽象方法),需要将该类定义抽象类.
2.特点:
1) 如果一个类中有抽象方法,那么该类一定是抽象类; 如果一个类是抽象类,那么该类中不一定存在抽象方法;
2)抽象类不能实例化(不能创建对象),所以要实例化就要创建子类对象,父类引用指向子类对象,通过子类实例化,
也即抽象类多态
3)抽象方法的格式:没有方法体的方法
权限修饰符 abstract 返回值类型 方法名(形式参数) ;
可以修饰类,可以修饰成员方法
4)抽象类 必须强制子类完成的事情!(将抽象类中所有的抽象方法重写)
abstract class Animal{//这个必须使用抽象来定义
//具体的动物才具体的吃的功能,将吃的功能抽象(没有方法体)
public abstract void eat() ;
public abstract void sleep();
}
3.注意事项:
1)抽象类没有抽象方法也可以,意义是不能创建对象,抽象类中的一些功能的返回值可能就是该类本身!
例如(日历类:Calendar它就是抽象类,里面的功能getInstance()非抽象方法,返回值就是该类本身)
2)abstract关键字 (定义成员方法的时候) 和final关键字冲突,和private关键字冲突和static关键字冲突,不能共存
四.接口interface
1.概念:体现的是事物的一种扩展性功能,也是一种定义的标准
2.注意事项:
1)接口中只能定义抽象方法
2)接口不能实例化,通过接口的子实现类来进行实例化! 接口多态! 实现关系(implements)
3)接口的子实现类 是具体类,只有具体类才可以实例化
4)接口可以多继承
//定义一个接口:动物跳高接口
interface AnimalJump{
public abstract void jump() ;
}
//定义一个接口的子实现类
class CatJumpImpl implements AnimalJump{
@Override
public void jump() {
System.out.println("猫可以跳高了...");
}
}
//测试类
public class InterfaceDemo {
public static void main(String[] args) {
//格式:接口名 对象名 =new 子实现类名(); 接口多态!
AnimalJump aj = new CatJumpImpl() ;
aj.jump();
}
}
3.接口中的成员特点:
成员方法: 只能是抽象方法,存在默认的修饰符,public abstract
成员变量: 只能是常量.存在默认的修饰符:public static final
构造方法: 不存在构造方法!
4.抽象类与接口的区别:
1)成员的区别
成员变量:
抽象类:既可以定义常量,也可以定义变量
接口:只能是常量,存在默认修饰符:public static final...
成员方法:
抽象类:既可以定义抽象方法,也可以定义非抽象方法
接口:只能是抽象方法,存在默认的修饰符:public abstract..
构造方法:
抽象类:存在构造方法,无参/有参,对数据进行构造初始化(分层初始化)
接口:没有构造方法
2)关系的区别
类与类之间
不管这个类是抽象类还是具体类,都继承关系(extends)
支持单继承,不支持多继承,可以多层继承
类与接口之间
实现关系(implements)
一个类继承另一个类的同时可以实现多个接口!
接口与接口之间
继承关系(extends)
支持单继承,以及多继承!
3)设计理念的区别
抽象类,----在抽象类多态中使用: 存在继承关系---- >体现的一种"is a"的关系
举例:
父类引用指向子类对象: Animal a = new Cat() ;
接口:体现的一个事物的扩展功能(额外功能),本身不具备的功能
子实现类 实现(implements)接口 :存在实现关系
体现的是一种"like a"的关系!
部分猫经过学习--->产生一个"跳高的功能" (跳高猫很像猫)