内部类
- 什么是内部类:一个类里面包含另一个类
- 内部类分类:成员内部类、局部内部类(包含匿名内部类)
成员内部类的定义和使用
-
内部类的定义
-
package view.study.demo5; /** * @Author: YiHua Lee * * 成员内部类的定义格式: * 修饰符 class 外部类名称 { * 修饰符 class 内部类名称 { * // ... * } * // ... * } * * 注意: * 内部类调用外部类,可以随意访问。 * 外部类调用内部类,需要借助内部类对象才可以访问内部类。 * */ public class Body { /** * 内部类 */ public static class Heart { /** * 内部类方法 */ public void beat() { System.out.println("心脏,蹦蹦跳"); System.out.println(name); // 内部类调用外部类,可以随意访问。 System.out.println(Body.getName()); Body.setName("胃"); } } /** * 外部类成员变量 */ private static String name; /** * 外部类方法 */ public void methodBody() { System.out.println("身体,哈哈哈"); } public static String getName() { return name; } public static void setName(String name) { Body.name = name; } }
-
-
如何使用成员内部类
-
间接方式:在外部类当中使用内部类,然后main只是调用外部类方法。
-
直接方式
-
内部类的同名变量访问
局部内部类的定义
/**
* @Author: YiHua Lee
*
* 局部内部类:
* 定义格式:
* 修饰符 class 类名称 {
* 修饰符 返回值类型 方法名称(参数列表) {
* class 局部内部类名称 {
* // 方法体...
* }
* }
* // ...
* }
*/
public class Outer1 {
public void method() {
// 局部内部类
class Inner {
int num = 10;
public void method() {
System.out.println(num);
}
}
new Inner().method(); // 只能在这个方法里面调用这个类
}
}
// 如果一个类定义在方法的内部,那么这个类就是一个局部内部类。
// 且这个类只能在方法内部使用,出了该方法,就不能用了。
局部内部类的final问题
局部内部类注意事项:
局部内部类是在方法内部的嘛,如果希望所在方法的局部变量,那么这个局部变量必须有【final关键词】
备注:
从Java 8+ 开始,只要局部变量事实不变,那么可以省略关键词 final
原因:
(1)new出来的对象是在堆内存中的,
(2)局部变量是跟着方法走的,在栈内存中,
(3)而方法运行结束之后,就会立刻出栈,局部变量也就会立刻消失,
(4)但是new出来的对象会在堆内存中持续存在,知道垃圾回收消失。
匿名内部类的定义及使用
实例理解
public interface anonymousInterface01 {
public abstract void method() ;
}
public class InterfaceImplements implements anonymousInterface01 {
@Override
public void method() {
System.out.println("实现类覆盖重写接口的抽象方法");
}
}
public class Demo01Anonymous {
public static void main(String[] args) {
// 多态方式创建对象
anonymousInterface01 obj1 = new InterfaceImplements();
// 调用实现类覆盖重写的接口的方法
obj1.method();
// 假如接口的实现类(或父类的子类)只需要使用唯一一次,
// 那么这种情况下就可以省略实现类(或子类)的定义,而改为使用匿名内部类。
anonymousInterface01 obj2 = new anonymousInterface01() {
@Override
public void method() {
System.out.println("我就使用一次,就不定义实现类了哈!!!");
}
};
// 调用匿名类覆盖重写的接口的方法
obj2.method();
}
}
匿名内部类的注意事项
对于匿名内部类
-
假如接口的实现类(或父类的子类)只需要使用唯一一次,那么这种情况下就可以省略实现类(或子类)的定义,而改为使用【匿名内部类】。
-
如果希望使用多次,那么就需要创建单独的实现类(或子类)了。
-
使用格式
接口名称 对象名 = new 接口名称() { // ... } 或 new 父类名称(参数列表) { // ... }
-
对 new 接口名称() {...} 的理解
- new 代表创建对象的动作
- 接口名称就是匿名内部类需要实现哪个接口
- {...} 是匿名内部类的内容
-
注意
- 匿名内部类只能使用唯一一次
- 要使用多次,请创建实现类(或子类)
类作为成员变量类型
实例理解
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;
}
public void attack() {
System.out.println("年龄为 " + age + " 岁的 " + name + " 正在使用 " + weapon.getCode() + " 突突突~~ " + "敌人");
}
}
public class DemoMain {
public static void main(String[] args) {
// 创建英雄
Hero hero = new Hero();
hero.setName("斯沃特");
hero.setAge(27);
// 给英雄配备武器
Weapon weapon = new Weapon();
weapon.setCode("AK-47(火麒麟)");
hero.setWeapon(weapon);
hero.attack();
}
}
接口作为成员变量类型
实例理解
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;
}
public void attack() {
System.out.println("年龄为 " + age + " 岁的 " + name + " 正在使用 " + weapon.getCode() + " 突突突~~ " + "敌人");
}
}
public class DemoMain2 {
public static void main(String[] args) {
// 创建英雄
Hero hero = new Hero();
hero.setName("斯沃特");
hero.setAge(27);
// 给英雄配备武器
Weapon weapon = new Weapon();
weapon.setCode("AK-47(火麒麟)");
hero.setWeapon(weapon);
hero.attack();
}
}
接口作为方法的参数或返回值
实例理解
import java.util.ArrayList;
import java.util.List;
/**
* @Author: YiHua Lee
* @CreateTime: 2019/12/18 21:12
*/
public class DemoArrayList {
public static void main(String[] args) {
// ArrayList<E> 类是 List<E> 接口的实现类
// 这里创建对象有使用多态的写法
ArrayList<String> arrayList = new ArrayList<>();
List<String> list = new ArrayList<>();
// 添加内容进集合
addList(arrayList);
addList(list);
// 遍历输出 arrayList
for (int i = 0; i < arrayList.size(); i++) {
System.out.println(arrayList.get(i));
}
System.out.println("===========================");
// 遍历输出 list
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
public static List<String> addList(List<String> list) {
list.add("大哥");
list.add("二哥");
list.add("三哥");
list.add("四哥");
return list;
}
}