一.多态
1.概念:一个事物在不同时刻体现出来的不同状态
2.多态的三个前提条件(缺一不可)
1)必须有继承关系 2)必须有重写(子类出现了父类一样的方法声明) 3)有父类引用指向子类对象(向上转型):Fu f = new Zi()
3.成员访问特点:
1)成员变量:编译看左边,运行看左边
2)成员方法(非静态的成员方法):编译看左,运行看右;由于存在方法重载,所以最终运行的是子类的成员方法。
3)静态成员方法:编译看左,运行看左;静态方法算不上方法重写,静态直接和类有关系
4)构造方法:对象进行初始化,由于是一种继承关系,还是分层初始化
class Fu{
public int num = 10;
//父类的成员方法
public void show(){
System.out.println("非静态父类方法。。。");
}
//静态方法
public static void method(){
System.out.println("静态的父类方法。。。");
}
}
//子类
class Zi extends Fu{
int num = 20;
public void show(){
System.out.println("非静态的子类方法。。。");
}
public static void method(){
System.out.println("静态的子类方法。。。");
}
}
//测试类
public class DuoTaiDemo {
public static void main(String[] args) {
//创建父类的对象:多态的形式
//父类引用指向子类对象:向上转型
Fu f = new Zi();
//访问成员变量,编译看左,运行看左
System.out.println(f.num);
System.out.println("----------");
//访问非静态成员方法,编译看左,运行看右
f.show();
System.out.println("----------");
//访问静态方法,编译看左,运行看左
f.method();
}
}
4.多态的好处
a.提高代码的维护性(由继承保证)
b.提高代码的扩展性(由多态保证)
java的开发原则:低耦合,高内聚
//父类
class Animal{
public void eat(){
System.out.println("eat...");
}
public void sleep(){
System.out.println("sleep...");
}
}
//猫类
class Cat extends Animal{
public void eat() {
System.out.println("cat eat fish。。。");
}
public void sleep() {
System.out.println("cat sleep。。。");
}
/**
* 优化改进,将猫吃和睡的方法封装成独立的功能
* */
public static void useCat(Cat c){
c.eat();
c.sleep();
}
}
//写一个动物的工具类
class AnimalTool{
//将类中无参构造私有化:目的是为了不让外界创建对象!
private AnimalTool() {
}
public static void useAnimal(Animal a){
a.eat();
a.sleep();
}
}
//狗类
class Dog extends Animal{
public void eat() {
//super.eat();
System.out.println("dog eat。。。");
}
public void sleep() {
//super.sleep();
System.out.println("dog sleep。。。");
}
/**
* 优化改进,将狗吃和睡的方法封装成独立的功能
* */
public static void useDog(Dog d){
d.eat();
d.sleep();
}
}
public class DuoTaiDemo2 {
public static void main(String[] args) {
Cat c1 = new Cat();
//c1.eat();
//c1.sleep();
Cat c2 = new Cat();
//c2.eat();
//c2.sleep();
//Cat.useCat(c1);
//Cat.useCat(c2);
Dog d1 = new Dog();
//d1.eat();
//d1.sleep();
Dog d2 = new Dog();
//d2.eat();
//d2.sleep();
//Dog.useDog(d1);
//Dog.useDog(d2);
//先创建AnimalToo类名直接调用方法
AnimalTool.useAnimal(c1);
AnimalTool.useAnimal(c2);
AnimalTool.useAnimal(d1);
AnimalTool.useAnimal(d2);
}
}
5.多态的弊端:不能访问子类特有的功能
class Animal3{
public void show(){
System.out.println("show Animal3---");
}
}
//子类
class Cat3 extends Animal3{
public void show(){
super.show(); //访问到父类的构造方法
System.out.println("show Cat3---");
}
//特有功能
public void playGame(){
System.out.println("cat catch mouse---");
}
}
public class DuotaiDemo3 {
public static void main(String[] args) {
Animal3 a = new Cat3(); //向上转型
a.show();
//多态弊端,不能访问子类特有功能
//a.playGame(); //编译出错
//解决办法 :1)创建子类具体对象
Cat3 c = new Cat3();
c.playGame();
//2)向下转型:父类的引用强制转换为子类的引用
Cat3 c1 = (Cat3) a;
c1.playGame();
}
}
如何解决多态的弊端?
注意:异常:OOM异常:严重:OutOfMemory:内存溢出!
解决方案:1)创建子类的具体对象,去访问自己的特有功能;虽然可以解决多态的弊端,但从内存角度考虑,需要创建子类对象,那么必须在堆内存开辟空间,耗费内存,会浪费空间;
2)多态的第三个前提条件:父类引用指向子类对象,那么可不可以将子类的引用指向父类的对象呢?
这是可以的:称为向下转型:将父类的引用强制转换为子类的引用:前提必须有父类的引用存在,向下转型依赖于向上转型!
二.抽象类
1.概念:每一个动物的吃和睡的功能不一样,不应该把动物类定义为一个具体类,而是给出一个声明(abstract)
当一个类中如果有抽象功能(抽象方法)的时候,那么这个类一定要定义为抽象类!
2.问题:一个抽象类中可以有非抽象方法吗?
一个抽象类中可以有抽象方法,也可以有非抽象的方法(记住!)
3.抽象类的特点:
1)抽象类不能实例化:抽象类不能创建对象
那么一个抽象类如何进行实例化?
通过抽象类多态形式:父类的引用指向子类对象,通过子类进行初始化!
2)抽象类多态:强制子类必须重写当前抽象的父类中所有的抽象方法,可以提高代码的维护性(里面的继承关系可以保证!)
4.抽象类的子类特点:
1)抽象类的子类是抽象类,那么没有意义!最终使用的是通过子类进行对象初始化的,如果子类被抽象修饰了,那么也不能创建对象,所以没有意义。
2)抽象类的子类必须是具体的类。
abstract class Animal{
//抽象方法:没有方法体的方法
public abstract void eat();
public abstract void sleep();
//具体的方法
public void show(){
System.out.println("show Animal......");
}
}
//抽象的子类;没有意义
/*abstract class Cat extends Animal{
}*/
//具体的子类,必须重写父类的方法
class Cat extends Animal{
@Override
public void eat() {
System.out.println("cat eat fish!");
}
@Override
public void sleep() {
System.out.println("cat sleep......");
}
}
//测试类
public class AbstractDemo {
public static void main(String[] args) {
//当前Animal已经被abstract修饰
//Animal a = new Animal();//Cannot instantiate the type Animal:抽象类不能实例化
Animal a = new Cat(); //Animal是抽象类--->通过抽象类多态进行实例化
a.eat();
a.sleep();
a.show();
}
}
注意:abstract不能和哪些关键字同时使用?
1)private
2)final:方法不能被重写
3)static:静态方法算不上方法重写
5.抽象类多态的练习:
分析:具体到抽象
程序员类:Programmer
成员变量:姓名,工号,工资
构造:有参,无参
成员方法:
setXXX()/getXXX(),
work()
经理类:Manager
成员变量:姓名,工号,工资
额外的属性:奖金
构造:有参,无参
成员方法:
setXXX()/getXXX(),
work()
抽取共性内容:独立的类:Employee(抽象类)普通员工和经理做的事情不一样,work();抽象方法
测试类:
程序员类:Programmer
成员变量:姓名,工号,工资
构造:有参,无参
成员方法:
setXXX()/getXXX(),
work()
经理类:Manager
成员变量:姓名,工号,工资
额外的属性:奖金
构造:有参,无参
成员方法:
setXXX()/getXXX(),
work()
抽取共性内容:独立的类:Employee(抽象类)普通员工和经理做的事情不一样,work();抽象方法
测试类:
Employee类
package day_08_10_23.abstract02;
public abstract class Employee {
//成员变量,定义为私有,提供对外访问的setXxx和getXxx方法
private String name;
private String num;
private int salary;
//无参
public Employee() {
}
//有参
public Employee(String name, String num, int salary) {
super();
this.name = name;
this.num = num;
this.salary = salary;
}
//公共的访问方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNum() {
return num;
}
public void setNum(String num) {
this.num = num;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
//抽象方法
public abstract void work();
//非抽象方法
public void show(){
System.out.println("name:"+name+"----"+"num:"+num);
}
}
Manager类package day_08_10_23.abstract02;
public class Manager extends Employee {
//无参
public Manager() {
}
//有参
public Manager(String name, String num, int salary) {
super(name, num, salary);
}
//重写抽象类所有的抽象方法
public void work() {
System.out.println("manager talk project!");
}
}
Programmer类package day_08_10_23.abstract02;
public class Programmer extends Employee {
//无参
public Programmer() {
}
//有参
public Programmer(String name, String num, int salary) {
super(name, num, salary);
}
//重写抽象类中的方法
public void work() {
System.out.println("programmer knock program!");
}
}
测试类
package day_08_10_23.abstract02;
//测试类
public class AbstractTest {
public static void main(String[] args) {
Employee m = new Manager("luona","18",8000);
m.work();
m.show();
Programmer p =new Programmer("hangeng","23",6000);
p.work();
p.show();
}
}
三.接口
1.概念:接口体现的是一种扩展功能。比如:猫可以跳高(并不是所有的猫都具有调高功能)
接口的表示:interface 接口名{
}
2.问题:接口里面的方法可以是非抽象方法吗?
不可以,只能是抽象方法 public abstract void jump();
3.特点:接口中没有构造方法;不能直接实例化(不能直接创建对象)
4.接口如何实例化:接口的子类实现
1)接口的子实现类是抽象类没有意义,子类不能创建对象,实际开发中用的就是子类对象进行实例化
2)接口的子实现类一定是非抽象类,可以通过子实现类进行实例化
5.接口多态:接口的引用指向子实现类对象
6.接口的子实现类和接口的关系:implements格式:class 子实现类名 implements 接口名{
}
子实现类的命名要见名知意:接口名+impl
package day_08_10_23.interface01;
interface Jump {
//非抽象方法:接口中不能有非抽象方法
/*public abstract void jump(){
System.out.println("cat can jump!");
}*/
public abstract void jump();
//构造方法:不能有
/*public jump(){
}*/
}
/*//子实现类是抽象类:没有意义,不能实例化
abstract class Cat implements Jump{
}*/
class Cat implements Jump{
@Override
public void jump() {
System.out.println("cat can jump!");
}
}
//测试类
public class InterfaceDemo1 {
public static void main(String[] args) {
//Jump j = new Jump(); //接口不能直接实例化
//通过接口多态的形式:接口的引用指向子实现类对象
Jump j = new Cat();
j.jump();
}
}
7.接口成员的特点:成员变量:只能是常量,存在默认修饰符:public static final(建议自己给出默认修饰符)
构造方法:接口没有构造方法
成员方法:接口中的成员方法默认修饰符:public abstract(建议自己给出默认修饰符)
package day_08_10_23.interface01;
interface Inter{
//成员变量
public static final int num1 = 10;
public static final int num2 = 20;
//抽象方法
public abstract void show();
public abstract void function();
}
//定义接口的子实现类:见名知意:接口名+impl
class InterImpl implements Inter{
@Override
public void show() {
System.out.println(num1);
System.out.println(num2);
}
@Override
public void function() {
System.out.println("function InterImpl...");
}
}
//测试类
public class InterfaceDemo2 {
public static void main(String[] args) {
//创建接口对象:接口多态的形式
Inter i = new InterImpl();
//i.num1 = 20; //当前num1变量被final修饰,不能再赋值
System.out.println(Inter.num1);
System.out.println(Inter.num2);
System.out.println("-----------");
i.show();
i.function();
}
}
8.类、接口之间的关系:类与类的关系:继承关系:extends,java中只支持单继承,不支持多继承,但是可以多层继承;
类与接口的关系:实现关系:implements,并且一个类在继承另一个类的同时,可以实现多个接口
(class 子实现类名 extends Object implements 接口名1,接口名2.......)
接口与接口的关系:继承关系:extends,可以是单继承,也可以是多继承!
面试题:接口和抽象类的区别?
1.成员的区别:
1)成员变量:
抽象类:成员变量可以是常量,也可以是变量
接口:成员变量只能是一常量:存在默认修饰符:public static final
2)构造方法:
抽象类:可以是有参构造,也可以是无参构造;作用:通过子类进行数据初始化(通过子类创建对象)
接口:没有构造方法
3)成员方法的区别:
抽象类:可以是抽象方法,也可以是非抽象方法
接口:只能是抽象方法:存在默认修饰符:public abstract
2.关系的区别:
1)类与类的关系:继承关系:extends,java中只支持单继承,不支持多继承,但是可以多层继承!
2)类与接口的关系:实现关系:implements,并且,一个类在继承另一个类的同时,可以实现多个接口
(class 子实现类名 enxtends Object implements 接口名1,接口名2...)
3)接口与接口的关系:继承关系:extends,可以支持单继承,也可以多继承!
3.设计理念的区别:
抽象类:体现的是一种“is a”的关系,存在继承关系!(抽象类多态)
接口:体现的是一种“like a”的关系,接口的一种扩展功能
接口:体现的是一种“like a”的关系,接口的一种扩展功能
接口练习1:老师和学生案例,加入抽烟的额外功能
老师teacher:公有成员:姓名,年龄
公有方法:上课
附加功能:抽烟
附加功能:抽烟
学生student:公有成员:姓名,年龄
公有方法:上课
公有方法:上课
分析:可以将老师和学生抽出一个抽象类Person,包含公有属性(name、age),公有方法定义为抽象方法(attedClass)
抽烟的额外功能定义为一个接口.
Person类
package day_08_10_23.interface03;
public abstract class Person {
private String name;
private int age;
//无参
public Person() {
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
//有参
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 abstract void attendClass();
}
Teacher类
package day_08_10_23.interface03;
public class Teacher extends Person {
public Teacher() {
super();
// TODO Auto-generated constructor stub
}
public Teacher(String name, int age) {
super(name, age);
// TODO Auto-generated constructor stub
}
@Override
public void attendClass() {
System.out.println("teacher teach!");
}
}
Student类package day_08_10_23.interface03;
public class Student extends Person {
public Student() {
super();
}
public Student(String name, int age) {
super(name, age);
}
@Override
public void attendClass() {
System.out.println("student get class");
}
}
Interface接口package day_08_10_23.interface03;
public interface Smoking {
public abstract void smok();
}
SmokingImplTeacher类package day_08_10_23.interface03;
public class SmokingImplTeacher extends Teacher implements Smoking {
@Override
public void smok() {
System.out.println("teacher smoking!");
}
}
测试类package day_08_10_23.interface03;
public class InterfaceTest {
public static void main(String[] args) {
Student s = new Student();
s.setName("罗娜");
s.setAge(20);
System.out.println(s.getName()+"----"+s.getAge());
s.attendClass();
System.out.println("---------------");
//通过有参构造初始化
s = new Student("李明",21);
System.out.println(s.getName()+"----"+s.getAge());
s.attendClass();
System.out.println("---------------");
SmokingImplTeacher st = new SmokingImplTeacher();
st.setName("differ");
st.setAge(23);
System.out.println(st.getName()+"----"+st.getAge());
st.attendClass();
st.smok();
}
}