概述
(一)继承
(二)抽象类
(三)接口
(四)多态
(五)final关键字
(六)权限修饰符
(七)内部类
注意:
面向对象的三大特征:封装性、继承性、多态性
(一)继承
继承是多态的前提,如果没有继承,就没有多态
在继承的关系中,子类就是一个父类,即子类可以被当作父类看待
例如父类是员工,子类是讲师,那么讲师就是一个员工
- demo01
我们简单实现一下上面的情况
Employee.java:
package com.zzq.extendstest;
/**
* 定义一个父类:员工类
*/
public class Employee {
public void method(){
System.out.println("方法执行");
}
}
Teacher.java:
package com.zzq.extendstest;
/**
* 定义一个子类:讲师类
*/
public class Teacher extends Employee{
}
Assistant.java:
package com.zzq.extendstest;
/**
* 定义了员工的另一个子类:助教类
*/
public class Assistant extends Employee{
}
ExtendsDemo01.java:
package com.zzq.extendstest;
public class ExtendsDemo01 {
public static void main(String[] args) {
//创建了一个子类对象
Teacher teacher = new Teacher();
//Teacher类当中虽然什么都没写,但是会继承来自父类的method()方法
teacher.method();//方法执行
//创建另一个子类助教的对象
Assistant assistant = new Assistant();
assistant.method();//方法执行
}
}
- demo02:
继承中成员变量的访问特点
package com.zzq.extendstest;
public class ExtendDemo02 {
public static void main(String[] args) {
Fu fu = new Fu();//创建父类对象
System.out.println(fu.numFu);//只能使用父类的东西
Zi zi = new Zi();//创建子类对象
System.out.println(zi.numFu);//可以使用父类的东西
System.out.println(zi.numZi);//也可以使用子类的东西
}
}
那如果父类的变量跟子类的变量重名呢?
/**
* 父类
*/
public class Fu {
int numFu = 10;
int num = 100;
public void methodFu() {
//因为本类当中有num,所以这里用的是本类的num
System.out.println(num);//100
}
}
/**
* 子类
*/
public class Zi extends Fu {
int numZi = 20;
int num = 200;
public void methodZi() {
//因为本类当中有num,所以这里用的是本类的num
System.out.println(num);//200
}
}
public class ExtendDemo02 {
public static void main(String[] args) {
Fu fu = new Fu();//创建父类对象
System.out.println(fu.num);//100
Zi zi = new Zi();//创建子类对象
System.out.println(zi.num);//200
}
}
有两种方法
1.直接通过子类对象访问成员变量
(等号左边是谁,就优先用谁,没有就继续向上找)
重名的变量是如此,重名的成员方法也是如此
2.通过成员方法间接访问成员变量(多态会详细讲)
(看new的是谁,优先用谁的方法,没有则向上找)
- demo03:
区分三种重名的变量
/**
* 父类
*/
public class Fu {
int num = 10;
}
总结:
局部变量:直接写成员变量名
本类的成员变量:this.成员变量名
父类的成员变量:super.成员变量名
注意:如果想要调用父类的重名方法,也可以用super.重名的方法()
- demo04:
其实重名的方法就是Override(重写)
重写的原则:
- 子类方法的返回值范围必须小于或等于父类方法的返回值范围
其中java.lang.Object是最大的
比如说:
父类的方法返回值类型是Object,子类重写的方法返回值类型是String是可以的;但是反过来就不可以,会报错的。 - 子类方法的权限修饰符必须大于或等于父类方法的权限修饰符
public > protected > (default) > private
注意:(default)不是关键字default,而是什么都不写,留空
- demo05:
继承中构造方法的访问特点
- 子类构造方法中有一个默认隐含的
super();
调用,所以一定是先调用了父类的构造方法,后执行子类的构造方法 - 可以通过super关键字来实现子类构造调用父类重载构造,如:
super(10);
- super的父类构造调用,必须是子类构造方法的第一个语句
- 一个子类构造只能调用一次父类构造
- 子类必须调用父类的构造方法,不写则赠送super();写了则用指定的super调用
- demo06:
super关键字的三种用法
/**
* 父类
*/
public class Fu {
int num = 10;
public Fu() {
}
public void method() {
System.out.println("父类方法");
}
}
- demo07:
this关键字的三种用法
super关键字用来访问父类内容,而this关键字用来访问本类内容
注意:
this(...);
调用也必须是构造方法的第一个语句,并且是唯一一个。- super和this两种构造调用,不能同时使用
因为this和super都要放在第一互相冲突,所以这里的super();
不再赠送
- demo08:
this和super关键字内存图解
Java继承的三个特征
(二)抽象类
抽象方法:加上abstract关键字,然后去掉大括号,直接分号结束
抽象方法所在的类必须要是抽象类才行,在class之前写上abstract即可
抽象类也能有普通方法
- demo01:
如何使用抽象类和抽象方法
1.不能直接new抽象类对象
2.必须用一个子类来继承抽象父类
3.子类必须覆盖重写(实现)抽象父类当中的所以抽象方法
4.创建子类对象进行使用
- demo02:
注意事项:
1.抽象类不能创建对象,只能创建其非抽象子类的对象
2.抽象类中可以有构造方法,是供子类创建对象时,初始化父类成员使用的
3.抽象类中不一定含有抽象方法,但是有抽象方法的类必定是抽象类
没有抽象方法的抽象类也不能直接创建对象,在一些特殊场景下有用途
4.抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类
5.假设爷爷有两个抽象方法,父亲(也是抽象类)只实现了一个,那么剩下一个儿子就要实现
(三)接口
接口就是多个类的公共规范
接口就是一种引用数据类型,最重要的内容就是其中的抽象方法
备注:换成了关键字interface之后,编译生成的字节码文件仍然是:.java --> .class
- 如果是Java 7,那么接口中可以包含的内容有:
1.常量
2.抽象方法 - 如果是Java 8,还可以包含有:
1.默认方法
2.静态方法 - 如果是Java 9,还可以额外包含有:
1.私有方法
- demo01:
接口的简单使用
/**
* 在任何版本的Java中,接口都能定义抽象方法
*/
public interface MyInterfaceAbstract {
//这是一个抽象方法
public abstract void methodAbs1();
//选择性省略关键字
abstract void methodAbs2();
public void methodAbs3();
void methodAbs4();
}
注意事项:
1.接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract
2.这两个关键字修饰符,可以选择性地省略
- demo02:
配合实现类使用
/**
* 实现类
*/
public class MyInterfaceAbsImpl implements MyInterfaceAbs {
@Override
public void methodAbs1() {
System.out.println("这是第一个方法");
}
@Override
public void methodAbs2() {
System.out.println("这是第二个方法");
}
@Override
public void methodAbs3() {
System.out.println("这是第三个方法");
}
@Override
public void methodAbs4() {
System.out.println("这是第四个方法");
}
}
/**
* 创建实现类对象
*/
public class Demo01 {
public static void main(String[] args) {
MyInterfaceAbsImpl myInterfaceAbs = new MyInterfaceAbsImpl();
myInterfaceAbs.methodAbs1();
myInterfaceAbs.methodAbs2();
myInterfaceAbs.methodAbs3();
myInterfaceAbs.methodAbs4();
}
}
注意事项:
1.接口不能直接使用,必须有一个实现类来实现接口
2.接口的实现类必须覆盖重写(实现)接口中的所有抽象方法
3.创建实现类的对象,进行使用
4.如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类自己必须是抽象类
- demo03:
从Java 8开始,接口中允许定义默认方法
备注:接口当中的默认方法,可以解决接口升级的问题
/**
* 接口类
*/
public interface MyInterfaceDefault {
//抽象
public abstract void methodAbs();
//默认方法
public default void methodDefault() {
System.out.println("新添加的默认方法");
}
}
/**
* 实现类A
*/
public class MyInterfaceDefaultImplA implements MyInterfaceDefault {
@Override
public void methodAbs() {
System.out.println("实现了抽象方法 AAA");
}
}
/**
* 实现类B
*/
public class MyInterfaceDefaultImplB implements MyInterfaceDefault {
@Override
public void methodAbs() {
System.out.println("实现了抽象方法 BBB");
}
}
public class Demo02 {
public static void main(String[] args) {
MyInterfaceDefaultImplA a = new MyInterfaceDefaultImplA();
MyInterfaceDefaultImplB b = new MyInterfaceDefaultImplB();
a.methodAbs();//实现了抽象方法 AAA
b.methodAbs();//实现了抽象方法 BBB
a.methodDefault();//新添加的默认方法
}
}
注意事项:
1.接口的默认方法,可以通过接口的实现类对象直接调用
2.接口的默认方法,也可以通过接口实现类进行覆盖重写
- demo04:
从Java 8开始,接口中允许定义静态方法
如果存在一些所有实现类实现方法都一样的方法,那么可以将其写成静态
/**
* 接口类
*/
public class MyInterfaceStatic {
public static void methodStatic() {
System.out.println("这是接口的静态方法");
}
}
public class Demo03 {
public static void main(String[] args) {
MyInterfaceStatic.methodStatic();//直接用类名调用
}
}
- demo05:
从Java 9开始,接口允许定义私有方法
1.普通私有方法可以解决多个默认方法之间重复代码问题
/**
* 接口类
*/
public interface MyInterfacePrivateA {
public default void methodDefault1() {
System.out.println("默认方法1");
common();
}
public default void methodDefault2() {
System.out.println("默认方法2");
common();
}
private void common() {
System.out.println("默认方法1");
System.out.println("AAA");
System.out.println("BBB");
System.out.println("CCC");
}
2.静态私有方法可以解决多个静态方法之间重复代码问题
/**
* 接口类
*/
public interface MyInterfacePrivateA {
public static void methodDefault1() {
System.out.println("默认方法1");
common();
}
public static void methodDefault2() {
System.out.println("默认方法2");
common();
}
private static void common() {
System.out.println("默认方法1");
System.out.println("AAA");
System.out.println("BBB");
System.out.println("CCC");
}
}
- demo06:
接口中定义常量
注意事项:
- 必须使用
public static final
三个关键字
如果省略了这三个关键字,效果也是一样的(都是不可修改) - 接口当中的常量必须赋值,不能不赋值
- 常量的命名必须全是大写,可用下划线
public interface MyInterfaceConst {
public static final int NUM_OF_MY_CLASS = 10;
}
public class Demo04 {
public static void main(String[] args) {
System.out.println(MyInterfaceConst.NUM_OF_MY_CLASS);
}
}
- demo07:
注意事项:
1.接口是没有静态代码块或者构造方法的,因为接口不能被new
2.一个类的直接父类是唯一的,但是一个类可以同时实现多个接口
3.如果实现类所实现的多个接口中,存在重复的抽象方法,那么只需要覆盖重写一次即可
4.如果实现类所实现的多个接口中,存在重复的默认方法,那么实现类必须对冲突的默认方法进行覆盖重写
5.一个类如果直接父类中的方法和接口中的默认方法产生了冲突,优先使用父类当中的方法 - demo08:
1.类与类之间是单继承的,直接父类只有一个
2.类与接口之间是多继承的,一个类可以实现多个接口
3.接口与接口之间是多继承的
(四)多态
extends继承或者implements实现是多态性的前提
代码当中体现多态性:父类引用指向子类对象
父类名称 对象名 = new 子类名称();
接口名称 对象名 = new 实现类名称();
- demo01:
多态的简单使用
public class Fu {
public void method() {
System.out.println("父类方法");
}
public void methodFu() {
System.out.println("父类特有方法");
}
}
public class Zi extends Fu {
@Override
public void method() {
System.out.println("子类方法");
}
}
public class MultiDemo01 {
public static void main(String[] args) {
//使用多态的写法
Fu obj = new Zi();
obj.method();//子类方法
obj.methodFu();//父类特有方法
}
}
多态:左父右子
1.当父类和子类都有相同的方法时,优先执行子类的
2.当父类拥有子类没有的方法时,执行父类的特有方法
- demo02:
多态中成员变量的使用特点
(前面继承的demo02有讲到)
访问成员变量的两种方式:
1.直接通过对象名称访问成员变量
(看等号左边是谁,就优先用谁,没有则向上找)
public class Fu {
int num = 10;
public void showNum() {
System.out.println(this.num);
}
}
public class Zi extends Fu {
int num = 20;
}
public class MultiDemo01 {
public static void main(String[] args) {
//使用多态的写法,父类引用指向子类对象
Fu obj = new Zi();
System.out.println(obj.num);//10
obj.showNum();//子类没有覆盖重写,方法属于父类,结果:10
}
}
2.间接通过成员方法访问成员变量
(看new的是谁,优先用谁的方法,没有则向上找)
- demo05:
口诀
- 成员方法:
编译看左,运行看右
只要方法是属于左边的就可以通过编译,不会报错;但是具体运行的是什么方法就看右边
如果右边没有,再往上找 - 成员变量:
编译看左,运行看左
只要变量是属于左边的就可以通过编译,不会报错;具体调用什么变量也是看左边
如果左边没有,再往上找
- demo04:
使用多态的好处
- demo05:
对象的向上转型
代码实现:
public abstract class Animal {
public abstract void eat();
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
public class MultiDemo02 {
public static void main(String[] args) {
//对象的向上转型就是父类引用指向父类对象
Animal animal = new Cat();
animal.eat();//猫吃鱼
}
}
但是向上转型有一个弊端,比如说给子类写一个特有方法,就无法调用特有方法!
因为我们把猫当成动物,并非所有动物都会捉老鼠
- demo06:
对象的向下转型
我们可以用向下转型来把动物还原回猫
代码实现:
同样,向下转型也有弊端,如下:
把原来是猫的动物转换成狗,会抛出类转换异常
- demo07:
如何才能知道一个父类的引用对象,本来是什么子类?
使用instanceof关键字进行分析
格式:
对象 instanceof 类型
这将会得到一个boolean值结果,也就是判断前面的对象能不能当作后面对象的实例
代码实现:
public class InstanceofDemo01 {
public static void main(String[] args) {
Animal animal = new Cat();//本来是一只猫
animal.eat();//猫吃鱼
//如果希望调用子类特有方法,需要向下转型
//判断一下父类引用animal本来是不是Dog
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.watchHouse();
}
//判断一下父类引用animal本来是不是Cat
if (animal instanceof Cat) {
Cat cat = (Cat) animal;
cat.catchMouse();
}
}
}
那么向上转型和向下转型有什么作用呢?
比如说下面这个方法,我是不知道我会接收到猫还是狗,我只知道接收到的一定是动物,那我可以用向下转型来判断;比如说把动物还原回狗
而别人如果给的是狗,即giveMeAPet(new Dog());
,则在传参的过程中自动使用了向上转型,把狗转变为动物
- demo08:
案例:笔记本电脑
USB接口作为统一规范,鼠标和键盘都向上转型成USB接口设备,笔记本再把它向下转型回原本的设备
代码实现:
public interface USB {
public abstract void open();//打开设备
public abstract void close();//关闭设备
}
public class Mouse implements USB {
@Override
public void open() {
System.out.println("打开鼠标");
}
@Override
public void close() {
System.out.println("关闭鼠标");
}
//特有方法
public void click() {
System.out.println("鼠标点击");
}
}
public class Keyboard implements USB {
@Override
public void open() {
System.out.println("打开键盘");
}
@Override
public void close() {
System.out.println("关闭键盘");
}
//特有方法
public void type() {
System.out.println("键盘输入");
}
}
public class Computer {
public void powerOn() {
System.out.println("笔记本电脑开机");
}
public void powerOff() {
System.out.println("笔记本电脑关机");
}
//使用USB设备的方法,使用接口作为方法的参数
public void useDevice(USB usb) {
usb.open();//打开设备
if (usb instanceof Mouse) {
Mouse mouse = (Mouse) usb;//向下转型
mouse.click();
} else if (usb instanceof Keyboard) {
Keyboard keyboard = (Keyboard) usb;//向下转型
keyboard.type();
}
usb.close();//关闭设备
}
}
public class DemoMain {
public static void main(String[] args) {
//创建一个笔记本电脑对象
Computer computer = new Computer();
computer.powerOn();//电脑开机
//准备一个鼠标,供电脑使用
//首先进行向上转型,把鼠标当作USB设备
USB usbMouse = new Mouse();
computer.useDevice(usbMouse);//打开鼠标,鼠标点击,关闭鼠标
//准备一个键盘
Keyboard keyboard = new Keyboard();//没有用多态写法
//方法参数是USB类型,传递进去的是实现类对象
//传参的过程中自动完成了向上转型
computer.useDevice(keyboard);//打开键盘,键盘输入,关闭键盘
computer.powerOff();//电脑关机
}
}
(五)final关键字
final关键字代表最终、不可改变的
常见四种用法:
1.可以用来修饰一个类
2.可以用来修饰一个方法
3.还可以用来修饰一个局部变量
4.还可以用来修饰一个成员变量
- demo01:
final关键字用于修饰类
含义:当前这个类不能有任何的子类
注意:一个类如果是final,那么其中所有的成员方法都无法进行覆盖重写
public final class MyClass {
public void method() {
System.out.println("方法执行");
}
}
- demo02:
final关键字用于修饰成员方法
当ifnal关键字用来修饰一个成员方法的时候,这个方法就是最终方法,也就是不能被覆盖重写
public class Fu {
public final void method() {
System.out.println("父类方法执行");
}
}
同时注意:final关键字和abstract关键字不能同时使用,互相矛盾,因为abstract是一定要被覆盖重写,而final是一定不能被覆盖重写
- demo03:
final关键字用来修饰局部变量
一旦使用final关键字来修饰局部变量,那么这个变量就不能进行更改
下面是正确写法,只要保证有唯一一次赋值即可
final int num;
num = 10;
注意:
- 对于基本类型来说,不可变说的是变量当中的数据不可改变
- 对于引用类型来说,不可变说的是变量当中的地址值不可改变
但是里面的内容是可以改变的,如下:
- demo04:
final关键字用来修饰成员变量
- 由于成员变量具有默认值,所以用了final的同时必须赋值,不会再给默认值了
- 对于final的成员变量,要么直接赋值,要么通过构造方法赋值
直接赋值的话,不能使用相应的set方法
如果使用构造方法赋值,则不允许存在空参构造方法,或者是该空参构造方法也有赋值
必须保证类当中所以重载的构造方法,都最终会对final的成员变量进行赋值
总结:尽管像String类型的成员变量有默认值NULL,但是被认为是没有意义的,所以报错。
(六)权限修饰符
Java中有四种修饰符
public
>protected
>(default)
>private
注意:(default)不是关键字,而是什么都不写
(七)内部类
如果一个事物的内部包含另一个事物,那么这就是一个类内部包含另一个类
例如:身体和心脏的关系;汽车和发动机的关系
分类:
1.成员内部类
2.局部内部类(包含匿名内部类)
注意:
1.内用外,随意访问
2.外用内,需要内部类对象
- demo01:
成员内部类的定义
public class Body {//外部类
public class Heart {//成员内部类
//内部类的方法
public void beat() {
System.out.println("心脏跳动");
System.out.println("我叫:" + name);//内部访问外部
}
}
//外部类的成员变量
private String name;
//外部类的方法
public void methodBody() {
System.out.println("外部类的方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- demo02:
成员内部类的使用
两种方式:
- 间接方式:
在外部类的方法当中,使用内部类;然后main只是调用外部类的方法
- 直接方式:
外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
- demo03:
内部类的同名变量访问
- demo04:
局部内部类的定义
如果一个类是定义在一个方法内部的,那么这就是一个局部内部类
“局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了
public class Outer {
public void methodOuter() {
class Inner {//局部内部类
int num = 10;
public void methodInner() {
System.out.println(num);//10
}
}
//只有自己所属的方法才能调用
Inner inner = new Inner();
inner.methodInner();
}
}
public class domain {
public static void main(String[] args) {
Outer obj = new Outer();
obj.methodOuter();//10
}
}
小结类的权限修饰符:
1.外部类:public / (default)
2.成员内部类:public / protected / (default) / private
3.局部内部类:因为只有自己所属的方法才能调用,所以什么都不能写,这并非(default)
- demo05:
局部内部类的final问题
局部内部类如果希望访问所在方法的局部变量,那么这个局部变量必须是有效final的
在JDK7之前,必须强制性写上final
从JDK8开始,只要局部变量事实不变,那么final关键字可以省略
在JDK7之后,可以不写final,但是必须保证不再改变,如果改变了依然报错
要加final的原因:
1.new出来的对象存在堆内存中
2.局部变量是跟着方法走的,在栈内存当中
3.方法运行结束之后,立刻出栈,局部变量就会立刻消失
4.new出来的对象会在堆当中持续存在,直到垃圾回收消失
5.只要保证变量一直不变,可以复制一份进对象,这样即使存在于栈中的局部变量消失了也无所谓
- demo06:
匿名内部类
如果接口的实现类(或者是父类的子类)只需要使用唯一的一次
那么这种情况下就可以省略该类的定义,而改为使用匿名内部类
匿名内部类的定义格式:
接口名称 对象名 = new 接口名称(){
//覆盖重写接口中所有的抽象方法
};
- 在介绍匿名内部类之前,先来看看普通的接口写法
public interface MyInterface {
public abstract void method();
}
public class MyInterfaceImpl implements MyInterface {
@Override
public void method() {
System.out.println("实现类覆盖重写了方法");
}
}
public class DemoMain {
public static void main(String[] args) {
MyInterfaceImpl impl = new MyInterfaceImpl();
impl.method();
}
}
- 在来看看使用了匿名内部类之后是怎么样的
public interface MyInterface {
public abstract void method();
}
public class DemoMain {
public static void main(String[] args) {
//使用匿名内部类
MyInterface obj = new MyInterface() {
@Override
public void method() {
System.out.println("匿名内部类实现了方法");
}
};
obj.method();
}
}
这样子我们可以省略掉实现类
对“new 接口名称(){…};”进行解析:
1.new代表创建对象的动作
2.接口名称就是匿名内部类需要实现的接口的名称
3.{…}这才是匿名内部类的内容
- demo07:
匿名内部类的注意事项
- 匿名内部类在创建对象的时候,只能使用唯一的一次
- 如果希望多次创建对象,而且类的内容意义的话,要么写两次匿名内部类(如下),要么像之前那样写一个实现类
- 使用了匿名内部类,而且省略了对象名称,也就是匿名对象
匿名对象:在调用方法的时候只能调用唯一一次,如果希望同一个对象调用多次方法,必须给对象起名字
- 匿名内部类是省略了实现类或者子类;匿名对象是省略了对象名称。
强调:匿名内部类和匿名对象不是一回事!
- demo08:
类作为成员变量类型
//武器类
public class Weapon {
private String code;//武器的代号
public Weapon() {
}
public Weapon(String code) {
this.code = code;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
把武器这个类当成成员变量的类型
//游戏当中的英雄角色类
public class Hero {
private String name;//英雄名字
private int age;//英雄的年龄
private Weapon weapon;//武器
public Hero() {
}
public Hero(String name, int age, Weapon weapon) {
this.name = name;
this.age = age;
this.weapon = weapon;
}
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 Weapon getWeapon() {
return weapon;
}
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
}
- demo09:
接口作为成员变量类型
public interface Skill {
public abstract void use();//释放技能的抽象方法
}
public class Hero {
private String name;//英雄的名称
private Skill skill;//英雄的技能
public Hero() {
}
public Hero(String name, Skill skill) {
this.name = name;
this.skill = skill;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Skill getSkill() {
return skill;
}
public void setSkill(Skill skill) {
this.skill = skill;
}
}
传统写法,使用实现类,如下:
public class SkillImpl implements Skill {
@Override
public void use() {
System.out.println("法术攻击");
}
}
public class DemoGame {
public static void main(String[] args) {
Hero hero = new Hero();
hero.setName("zhangsan");
//设置英雄的技能
hero.setSkill(new SkillImpl());
}
}
如果使用匿名内部类,则可以省略实现类,如下:
public class DemoGame {
public static void main(String[] args) {
Hero hero = new Hero();
hero.setName("zhangsan");
//设置英雄的技能
hero.setSkill(new Skill() {
@Override
public void use() {
System.out.println("法术攻击");
}
});
}
}
- demo10:
接口作为方法的参数或返回值
public class DemoInterface {
public static void main(String[] args) {
//左边是接口名称,右边是实现类名称,这就是多态写法
List<String> list = new ArrayList<>();
List<String> result = addNames(list);
for (int i = 0; i < result.size(); i++) {
System.out.println(result.get(i));
}
}
public static List<String> addNames(List<String> list) {
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
return list;
}
}