100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > java第四弹 多态 final static 代码块 抽象类 匿名类 接口 Java8新特性:接口增强

java第四弹 多态 final static 代码块 抽象类 匿名类 接口 Java8新特性:接口增强

时间:2022-05-20 21:03:05

相关推荐

java第四弹 多态 final static 代码块 抽象类 匿名类 接口 Java8新特性:接口增强

1.多态

多态的理解

(1)同一个动作作用于不同的对象产生的不同的行为,比如不同子类对父类的不同的重写。

(2)多态就是一个对象的多种形态。多态的体现

(1)基于继承的实现,不同子类重写了父类方法之后体现不同的形式。

(2)接口的实现。形成多态的条件

(1)继承:子类去继承父类。

(2)重写:子类重写父类的方法。

(3)重载:同一个方法名,形参列表不同,实现的功能也不同。

(4)子类对象的多态性:父类的引用指向子类的实例。程序分为两种状态,一种是编译时状态,一种是运行时状态。

举例:Pet p1 = new Dog(“泰迪”, “小泰”);

对于多态来说,编译时看左边,会把p1看作是宠物类对象,运行时看右边,堆中实际存放的类型是Dog类型。向上转型和向下转型

(1)向上转型(小转大):将子类赋值给父类的引用,可以自动类型转换,例如Pet p1 = new Dog(“泰迪”, “小泰”);

(2)向下转型(大转小):将父类转换为子类,需要强制类型转换,例如Dog dog1 = (Dog) p1;多态的类型

(1)编译时(看左边)多态:方法重载(在编译期间,调用相同的方法名,根据不同的参数列表来确定调用的是哪个方法)。

(2)运行时(看右边)多态:方法的重写(只有在运行期间才确定使用的对象类型,才能确定变量的引用指向哪哪种对象的实例)。补充instanceof运算符

该运算符用来判断一个对象是否属于一个类或者实现了一个接口,返回true挥着false。在强制类型转换之前,通过此运算符检查对象的真实类型,可以避免类型转换异常,从而提高代码健壮性。

这么说太抽象,用代码来说明一下👇

Pet父类

public class Pet {private String name;protected int health = 100;//健康值public Pet() {}public Pet(String name) {this.name = name;}public Pet(int health) {this.health = health;}public Pet(String name, int health) {this.name = name;this.health = health;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getHealth() {return health;}public void setHealth(int health) {this.health = health;}//宠物吃食public void eat() {System.out.println("宠物吃食");}//描述宠物信息public void info() {System.out.println("我的昵称是" + this.name + ",我的健康值是" + this.health);}}

Dog子类

public class Dog extends Pet {//狗勾的有的属性public String stain;//品种//无参构造方法public Dog() {}//两个参数的构造方法,其中name继承自父类public Dog(String stain, String name) {super(name);this.stain = stain;}public String getStain() {return stain;}public void setStain(String stain) {this.stain = stain;}//重写宠物吃食的方法public void eat() {super.health = super.health + 3;System.out.println("狗勾吃饱了,健康值加3");}//重写宠物info的方法public void info() {super.info();System.out.println("我的品种是" + this.stain);}//Dog类独有的方法public void sleep() {System.out.println("狗勾在呼呼呼的大睡");}}

Penguin子类

public class Penguin extends Pet {//企鹅独有的属性private int age;//无参构造方法public Penguin() {}//两个参数的构造方法,其中name继承自父类public Penguin(int age, String name,) {super(name);this.age = age;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}//重写宠物吃食的方法public void eat() {super.health = super.health + 5;System.out.println("企鹅🐧吃饱了,健康值加5");}重写宠物info的方法public void info() {super.info();System.out.println("我的年龄是" + this.age);}//Penguin类独有的方法public void swimming(){System.out.println("企鹅🐧在游泳");}}

Master主人类

public class Master {private String hostName;//主人姓名public String getHostName() {return hostName;}public void setHostName(String hostName) {this.hostName = hostName;}public Master() {}public Master(String hostName) {this.hostName = hostName;}//给狗🐕喂食public void feed(Dog dog) {dog.eat();}//给企鹅🐧喂食public void feed(Penguin penguin) {penguin.eat();}}

TestMaster测试类

public class TestMaster {public static void main(String[] args) {//创建一个宠物类Pet p = new Pet("开心");p.eat();p.info();Dog dog = new Dog("金毛", "小金");dog.info();Penguin pg = new Penguin(12, "小鹅");pg.info();//不同子类对父类的不同的重写Master m = new Master();m.feed(dog);m.feed(pg);System.out.println("==========================子类对象的多态性");//子类对象的多态性:父类的引用指向子类的实例//这时候p1只能调用重写的方法(父类的方法)Pet p1 = new Dog("泰迪", "小泰");p1.info();//调用Dog重写的info()方法//p1可不可以调用狗类独有的方法? 不可以。//编译期间,程序会把p1看成是Pet对象,而Pet类里没有sleep()方法//现在就想用p1调用sleep方法怎么做?进行向下转型强制类型转换Dog dog1 = (Dog) p1;//向下转型(大转小)dog1.sleep();//Penguin pg1 = (Penguin) p1;//p1已经转成了Dog类型,不能再转成Penguin//使用instanceof检查p1类型,然后做相应的强制类型转换if (p1 instanceof Dog) {Dog dog2 = (Dog) p1;dog2.sleep();} else if (p1 instanceof Penguin) {Penguin pg1 = (Penguin) p1;pg1.swimming();}}

Pet p1 = new Dog(“泰迪”, “小泰”);其实是一种向下转型,这时候子类p1只能调用父类的方法,如果子类重写了,那么就调用子类重写后的方法,不能调用子类独有的方法。

那问题来了,怎么才能让p1调用独有的方法呢,这就得就得通过向下转型,Dog dog1 = (Dog) p1;将p1强制类型转换为Dog类型,然后就可以调用Dog独有的方法,但是不能调用父类的方法。

2.final

final可以用来修饰类、方法、成员变量和局部变量。

final修饰类,表示这个类是最终类,不能被继承。

父类

public final class Person {}

子类在继承Person类的时候会报错👇

修饰方法,表示这个方法不能被重写。

父类

public class Person {

public final void sleep() {

System.out.println(“人在睡觉”);

}

}

重写sleep方法时会报错👇

修饰成员变量。

修饰成员变量后,成员不再有默认值,所以必须要赋值,并且赋值之后不能再修改,所以该成员变量没有setter方法,只有getter方法。

public class Person {

//private final String name;//没有赋值,所以报错。

private final String name = “talent”;

}

修饰局部变量(一般用大写字母)。

修饰局部变量后,该变量就成了常量,一旦修改,不可改变。

public static void main(String[] args) {

final int A = 10;

//A = 20;//报错

final int B;

B = 20;

}

3.static

Person person = new Person();当我们通过new关键字创建对象的时候,这时候系统才会分配内存空间给每个对象,其方法才可以供外部调用。

但是,我们有时候希望无论是否产生了对象或者无论产生了多少对象,某些特定的数据在内存中只有一份。

例如所有的中国人都有个国家名称nation,每个中国人都共享这个国家名称,那么每个中国人都可以共享这个属性。

static:静态的。static可以修饰变量、方法和代码块。static修饰变量后,变量变成静态变量。

(1)按照是否使用static进行修饰,可以分为:实例变量(创建了实例之后才能使用)和静态变量。 实例变量:创建了多个对象,每个对象都独立有一套类中的非静态变量(实例变量)。每个对象的非静态变量互不影响。静态变量:创建了多个对象,多个对象共享一个静态变量,当其中一个对象修改了静态变量,会导致其他对象的静态变量改变。

(2)static修饰变量属性不再属于对象,而是属于类,只要是这个类创建的对象,都可以共享该静态变量;静态变量属于对象。静态变量随着类的加载而加载;实例变量随着对象的创建而加载。静态变量的加载时间早于对象的创建。由于类只会加载一次,静态变量在内存中只有一份。 static修饰方法

(1)static修饰方法后,这个方法就不再属于对象,而是属于类。

(2)静态方法是随着类的加载而加载,‘类名.方法名’。

(3)静态方法只能调用静态变量和静态方法,非静态方法能调用非静态变量和非静态方法,也能调用静态变量和静态方法。因为静态变量是在类加载的时候加载静态方法,而实例变量是在对象创建之后才加载实例变量,当静态方法调用实例变量的时候,实例变量还没有被加载,所以不能在静态方法里调用实例变量。在静态方法里面可以使用this和super吗?

不可以,因为这两个关键字是有了对象以后才存在,而静态方法早于对象的创建。开发中,如何确定一个属性使用static进行修饰呢?

如果一个属性需要被多个对象共享,使用static进行修饰。开发中,如何确定一个方法使用static进行修饰呢?

工具类会使用static进行修饰方法。如jdbc工具类和connection连接对象,操作静态变量的方法一般都用static修饰。

请看代码👇

public class Chinese {String name;int age;static String nation;public void eat(){System.out.println("在吃饭");//调用静态变量和实例变量nation = "china";age = 12;//调用静态方法sleep();}public static void sleep(){System.out.println("在睡觉");//静态方法只能调用静态变量nation = "china";//age = 12;//静态方不能调用实例变量//eat();静态方不能调用实例方法}}public class TestChinese {public static void main(String[] args) {Chinese.nation = "中国";Chinese.sleep();Chinese c = new Chinese();c.name = "张三";c.age = 20;//c.nation = "中国";Chinese c2 = new Chinese();c2.name = "李四";c2.age = 40;//c2的年龄不会影响c1的age,每个对象都独一份c2.nation = "china";//c2的nation会影响c1的nationSystem.out.println(c.nation);//chinaSystem.out.println(c2.nation);//china}}

4.代码块

代码块也叫做初始化块。

代码块的作用就是初始化类和对象。代码块只能通过static修饰,修饰之后成为静态代码块。可以看成匿名方法。

4.1.静态代码块

随着类的加载而加载,它是属于类的。可以写输出语句。静态代码块的执行要优先于非静态代码块的执行。静态代码块里只能调用静态变量和静态方法。比如jdbc对数据库连接池进行初始化时会用到静态代码块。

4.2.非静态代码块

随着对象的创建而加载,它是属于对象的。可以写输出语句。创建了几个对象,非静态代码块就加载几次。作用:可以在创建对象的同时,给对象的属性进行初始化。

请看代码👇

package com.hpe.java2;public class Animal {String name;int age;static String desc = "我是一只动物";//非静态代码块{name = "小白";age = 20;//调用静态变量desc = "我是一只小动物";//调用静态方法show();System.out.println("我是非静态代码块");}//静态代码块static{System.out.println("我是静态代码块");//调用非静态变量和非静态方法//age = 20;//报错//eat();//报错//调用静态变量和静态方法desc = "hehe";show();}public Animal() {}public Animal(String name, int age) {this.name = name;this.age = age;}public void eat(){System.out.println("吃饭");}public static void show(){System.out.println("我是一只可爱的动物");}}package com.hpe.java2;public class TestAnimal {public static void main(String[] args) {Animal animal = new Animal();Animal animal1 = new Animal();}}package com.hpe.java2;public class TestAnimal {public static void main(String[] args) {Animal animal = new Animal();Animal animal1 = new Animal();}}

5.抽象类

随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更通用。

类的设计应该保证父类和子类能够共享特征。有时将一个父类设计的非常的抽象,以至于他没有具体的实例,这样的类叫做抽象类。

用abstract修饰一个类时,这个类叫做抽象类;用abstract修饰一个方法时,这个方法叫做抽象方法。

抽象方法:public abstract void eat();但这个方法只有方法的定义,没有方法的实现。

抽象类:在class前加abstract

特点:

抽象方法所在的类必须是抽象类。抽象类不能实例化。如果要实现抽象类,必须创建一个非抽象子类去继承抽象类。子类继承抽象类,必须重写抽象类中所有的抽象方法(子类若是抽象类,则不用重写)。抽象类里可以定义普通方法。抽象类里可以定义构造方法。

注意:

不能用abstract修饰属性、构造器、私有方法、静态方法、final的方法。

举例说明

Animal是抽象类。

Dog是抽象类,继承Animal。

Cat是普通类,并继承Animal。

Dog2Ha是普通类,继承Dog。

请看代码👇

package com.hpe.java;public abstract class Animal {//动物吃饭,就是一个抽象的,因为我们不知道具体是什么动物。//比如狗吃骨头,猫吃鱼🐟public abstract void eat();public abstract void sleep();//抽象类中可以定义普通方法public void show() {System.out.println("描述");}//可以定义构造方法吗? 可以!//所有类最终继承Object类//如果不能定义构造方法,也就代表不能使用Object里定义的方法和属性了public Animal() {super();}}package com.hpe.java;//重写父类方法快捷键crtl+i/o//Dog也是抽象类,对于Animal中的所有抽象方法,可以重写,可以不重写,也可以不全重写//但是没有重写的抽象方法,交给下一代重写public abstract class Dog extends Animal{//抽象类Dog类重写了Animal的eat(),sleep()交给Dog2Ha重写@Overridepublic void eat() {System.out.println("汪星人喜欢吃骨头");}}package com.hpe.java;public class Cat extends Animal{@Overridepublic void eat() {System.out.println("喵星人喜欢吃鱼");}@Overridepublic void sleep() {System.out.println("喵星人在睡觉");}}package com.hpe.java;public class Dog2Ha extends Dog{@Overridepublic void sleep() {System.out.println("我是二哈,我智商低");}}package com.hpe.java;public class TestAnimal {public static void main(String[] args) {//抽象类不能被实例化,因为动物是一个抽象的概念//Animal animal = new Animal();//报错//Dog也是一个抽象类,不能被实例化//Animal dog = new Dog();//多态:父类的引用指向子类的实例Animal dog = new Dog2Ha();dog.eat();dog.show();Animal cat = new Cat();cat.eat();}}

一般类和抽象类的区别:

一般类有足够的信息描述事务;抽象类描述事物的信息可能不足。一般类中不能定义抽象方法,只能定义非抽象方法;抽象类中可定义抽象方法,也可定义非抽象方法。一般类可以被实例化,抽象类不可以被实例化。

6.匿名xx

匿名类有两种:

与子类有关的匿名类与接口有关的匿名类

下面用代码说明与子类有关的匿名类👇

package com.hpe.java1;public abstract class Person {public abstract void eat();public abstract void sleep();}package com.hpe.java1;public class Student extends Person{@Overridepublic void eat() {System.out.println("学生在吃饭");}@Overridepublic void sleep() {System.out.println("学生在睡觉");}}package com.hpe.java1;public class TestPerson {public static void main(String[] args) {Person person = new Student();method(person);//person是非匿名对象 Student是非匿名类method(new Student());//匿名对象,只能用一次//这里之所以说只能用一次,是因为再创建一个匿名对象的话,虽然不会报错,但两个匿名对象不是同一个对象。//其实是new了一个子类,注意这里是子类,相当于Student类,只是这个子类没有名字//创建了一个匿名子类的对象person1//匿名子类非匿名对象Person person1 = new Person() {@Overridepublic void eat() {System.out.println("这里是匿名子类的eat方法");}@Overridepublic void sleep() {System.out.println("这里是匿名子类的sleep方法");}};person1.eat();//匿名子类的最简单的写法,可以用,但是不建议用。//匿名子类匿名对象method(new Person() {@Overridepublic void eat() {}@Overridepublic void sleep() {}});}public static void method(Person person) {System.out.println("学生");}}

与接口有关的匿名类和上面那种几乎一样,只需把抽象类Person类变成接口即可。

7.接口

我们对电脑已经非常熟悉了,众所周知,电脑具有拍照和播放光碟的功能。现在有一个TakingPhoto类,它提供拍照的功能;还有一个PlayVCD类,它提供了播放光碟的功能。电脑同时具有这两个类的提供的功能。因此我们希望定义一个Computer类,继承TakingPhoto和PlayVCD类。但此时问题就出现了 java中是不允许多重继承的!!!

为了解决这个问题,Java提出了接口的方式,作为“替代版”的多重继承。

1.接口是什么?

(1)多个类之间的公共规范。

(2)接口的出现为了解决java不能多继承的问题。

(3)接口里的方法都是抽象方法,它相当于一个特殊的抽象类。

2.怎么定义一个接口?

public interface Traffic{}

3.接口的特点

(1)接口里的成员变量都是常量,默认会加上public static final。

(2)接口里的方法都是抽象方法(默认方法除外–jdk1.8新特性),默认会加上public abstract。

(3)接口不能实例化,抽象类通过继承实现,接口通过创建一个类去实现接口。

(4)接口里面不能定义普通方法,可以定义默认方法。

(5)接口不能定义构造方法。

(6)一个接口可以继承一个接口,并且可以继承多个接口。

4.实现类

(1)实现接口的类叫做实现类,写法例如:public class Car implements Traffic。

(2)实现类要重写接口里面所有的抽象方法(实现类是抽象类除外)。

(3)一个是实现类可以实现多个接口。

(4)如果一个类再继承一个类的同时实现一个接口,必须先继承后实现。

5.面试题:接口和抽象类的相同点和不同点。

相同点:

(1)接口和抽象类都不能被实例化。只能被其他类实现和继承。

(2)接口和抽象类都可以包含抽象方法,实现接口和抽象类的类都必须实现这些抽象方法(实现类是抽象类除外)。

(3)接口和抽象类都可以有静态方法,通过接口名和类名调用。

不同点:

(1)接口里只能包含抽象方法,能包含默认方法,能包含静态方法,不能包含普通方法;抽象类则完全可以包含普通的方法。

(2)接口里只能定义静态常量属性,不能定义普通属性;抽象类里既可以定义普通属性,也可以定义静态常量。

(3)接口不包含构造函数;抽象类可以包含构造函数,抽象类里的构造函数并不是用于创建对象,而是让其子类调用这些构造函数来完成属于抽象类的初始化操作。

(4)接口不包含初始化块,但抽象类可以包含初始化块。

(5)一个类最多只能有一个直接父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java的单继承不足。

用一张图来彻底说明接口和抽象类在开发中分别的作用👇。

通过代码来解释简单说明一下👇。

Traffic接口定义了车的一系列方法。

package com.hpe.java3;public interface Traffic {int a = 10;//这是常量public static final int b = 10;//两种方式相同,都表示常量//车启动public abstract void start();//这是一个抽象方法//车加速abstract void add();//这也是一个抽象方法//车行驶public void run();//这也是一个抽象方法//车停止void stop();//jdk1.8新特性-----默认方法public default void m1() {}//接口里不能有构造方法//public Traffic(){//}}

Car类实现了Traffic。

package com.hpe.java3;//汽车类public class Car implements Traffic, Oil {//重写Traffic的方法@Overridepublic void start() {System.out.println("汽车启动了...");}@Overridepublic void add() {System.out.println("汽车加速了...");}@Overridepublic void run() {System.out.println("汽车行驶了...");}@Overridepublic void stop() {System.out.println("汽车停止了...");}//重写Oil的方法@Overridepublic void addOil() {System.out.println("汽车在加油...");}}

EVs类实现了Traffic。

package com.hpe.java3;//电动车public class EVs implements Traffic {@Overridepublic void start() {System.out.println("电动车启动了...");}@Overridepublic void add() {System.out.println("电动车加速了...");}@Overridepublic void run() {System.out.println("电动车行驶了...");}@Overridepublic void stop() {System.out.println("电动车停止了...");}}

测试一下。

package com.hpe.java3;public class Test {public static void main(String[] args) {//Traffic traffic = new Traffic();//抽象类不能实例化//创建汽车对象Car car = new Car();car.start();car.run();car.add();car.stop();//多态//一般使用下面这种方式//接口引用指向实现类实例Traffic evs = new EVs();evs.start();evs.run();evs.add();evs.stop();}}

8.Java8新特性:接口增强

Java 8 对接口做了进一步的增强。

接口中可以添加使用 default 关键字修饰的非抽象方法,即默认方法(或扩展方法)。接口里可以声明静态方法,并且可以实现。

下面先说一下默认方法。

接口冲突。 当一个类实现两个接口,并且这两个接口里有同名(包括参数相同)的默认方法,那么这个实现类必须要重写这个默认方法,否者无法通过编译。

package com.hpe.java6;

public interface MyFun1 {

default String getName() {

return “interface MyFun1”;

}

}

package com.hpe.java6;

public interface MyFun2 {

default String getName() {

return “interface MyFun2”;

}

}

package com.hpe.java6;

public class SubClass implements MyFun2, MyFun1{

@Override

public String getName() {

return “class SubClass Override”;

}

}

package com.hpe.java6;

public class Test {

public static void main(String[] args) {

SubClass sub = new SubClass();

System.out.println(sub.getName("hello : "));//hello : class SubClass Override

}

}

注意:如果要想调用接口的默认方法,只需要修改SubClass类即可👇。

package com.hpe.java6;public class SubClass implements MyFun1,MyFun2{@Overridepublic String getName(String str) {//注意这里super的写法return MyFun1.super.getName(str);}}package com.hpe.java6;public class Test {public static void main(String[] args) {SubClass sub = new SubClass();System.out.println(sub.getName("hello : "));//hello : interface MyFun1}}

超类优先。当继承的父类和实现的接口中有相同签名的方法时,不用重写接口的方法,优先使用父类的方法。

package com.hpe.java6;

public interface MyFun1 {

default String getName(String str) {

return str + “interface MyFun1”;

}

}

package com.hpe.java6;

public class MyClass {

public String getName(String str) {

return str + “class MyClass”;

}

}

package com.hpe.java6;

public class SubClass extends MyClass implements MyFun1{

}

package com.hpe.java6;

public class Test {

public static void main(String[] args) {

SubClass sub = new SubClass();

System.out.println(sub.getName("hello : "));//hello : class MyClass

}

}

再来说一下接口里的静态方法。

比较简单直接上代码👇。

public interface MyInterface {public static void show(){System.out.println("接口中的静态方法");}}public class Test {public static void main(String[] args) {MyInterface.show();//接口中的静态方法}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。