1. 内部类的概念与分类
如果一个事物的内部包含了另一个事物,那么就是一个类内部包含了另外一个类。
例如:身体和心脏的关系,汽车和发动机的关系。
分类:
- 成员内部类
- 局部内部类(包含匿名内部类)
2. 成员内部类的定义及其使用
成员内部类的定义格式:
1 2 3 4 5 6
| 修饰符 class 类名称 { 修饰符 class 内部类名称 { } }
|
如何使用成员内部类?两种方式:
间接方式:在外部类的方法当中,使用内部类;然后main只是调用外部类的方法
直接方式:记住公式
1 2
| 类名称 对象名 = new 类名称(); 外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
|
注意:
内用外,随意访问;
外用内,一定需要借助内部类对象
Body.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class Body { public void methodBody() { System.out.println("外部类的方法"); new Heart().beat(); } private String name; public Body() { this.name="娃哈哈"; } public Body(String name) { this.name=name; } public class Heart{ public void beat() { System.out.println("心脏跳动:嘭嘭嘭"); System.out.println("我叫:"+name); } } }
|
Main.java
1 2 3 4 5 6
| public static void main(String[] args) { new Body().methodBody(); new Body().new Heart().beat(); }
|
如果外部类跟内部类的成员变量重复了咋整?
1 2 3 4 5 6 7 8 9 10 11 12
| public class Outer { int num=10; public class Inner /*extends Object*/ { int num=20; public void methodInner(){ int num=30; System.out.println(num); System.out.println(this.num); System.out.println(Outer.this.num); } } }
|
如果重现重名现象
1
| 外部类名称.this.外部类成员变量名//访问外部类里面的变量
|
Main.java
1 2 3 4 5
| public static void main(String[] args){ new Outer().new Inner().methodInner(); Outer.Inner inner = new Outer().new Inner(); }
|
3. 局部内部类的定义及其使用
如果一个类是定义在一个方法内部的,那么这就是一个局部内部类
局部:只有当前所属的方法才能使用他,出了这个方法外面就不能用了
定义格式:
1 2 3 4 5 6 7
| 修饰符 class 外部类名称 { 修饰符 返回值类型 外部类方法名称(参数列表){ class 局部内部类名称 { //.... } } }
|
类的权限修饰符:
public>protected>(default)>private
定义一个类,权限修饰符规则:
- 外部类:只能用public/(default)
- 成员内部类:public/protected/(default)/private
- 局部内部类:什么都不写
Outer01.java
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Outer01 { public void methodOuter() { class Inner { int num=10; public void innerMethod() { System.out.println(num); } } new Inner().innerMethod(); } }
|
Main.java
1 2 3
| public static void main(String[] args) { new Outer01().methodOuter(); }
|
局部内部类,如果希望访问所在方法的局部变量,那么这个局部变量必须是有效final的
有效final:即使没写final,如果只赋值一次,也是有效final。写上final会更保险,更好
备注:从Java 8开始,只要局部变量不变,那么final就可以省略。
原因:
- new出来的对象在堆内存中
- 局部变量是跟着方法走的,在栈内存中
- 方法运行结束之后,立刻出栈,局部变量就会消失
- new出来的对象会在堆中持续存在,直至垃圾回收消失
Outer02.java
1 2 3 4 5 6 7 8 9 10 11 12
| public class Outer02 { public void methodOuter() { int num=10; class Inner { public void methodInner() { System.out.println(num); } } new Inner().methodInner(); } }
|
Main.java
1 2 3
| public static void main(String[] args) { new Outer02().methodOuter(); }
|
4. 匿名内部类(属于局部内部类)的定义及其使用
如果接口的实现类,或者是父类的子类,只需要使用唯一的一次。
那么这种情况下,就可以省略该类的定义,而使用匿名内部类。
匿名内部类的定义格式:
1 2 3
| 接口名称 对象名 = new 接口名称(){ //覆盖重写接口中所有的抽象方法 }
|
new 接口名称()表示要继承的接口,后面的{}才是匿名内部类
对格式“new 接口名称(){…}”进行解析:
- new代表创建对象的动作
- 接口名称就是匿名内部类要实现的接口
- {…}才是匿名内部类的内容
注意:
- 匿名内部类,在创建对象的时候,只能使用唯一一次。
如果希望多次创建对象,而且类的内容一样的话,那么就必须使用单独定义的实现类了 - 匿名对象,在调用方法的时候,只能调用唯一一次
如果希望同一个对象,调用多次方法,那么必须给对象起名 - 匿名内部类是省略了实现类或者子类,匿名对象是省略了对象名称
强调:匿名内部类和匿名对象不是一回事
匿名内部类有对象名称,匿名对象没有
MyInterface.java
1 2 3 4 5
| public interface MyInterface { void methodAbs(); void method(); }
|
MyInterfaceImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class MyInterfaceImpl implements MyInterface {
@Override public void methodAbs() { System.out.println("实现类覆盖重写了方法"); }
@Override public void method() { System.out.println("实现类覆盖重写了方法"); }
}
|
Main.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public static void main(String[] args) { MyInterface impl=new MyInterface() { @Override public void methodAbs() { System.out.println("匿名内部类覆盖重写了方法"); }
@Override public void method() { System.out.println("匿名内部类覆盖重写了方法"); } }; impl.methodAbs(); impl.method(); System.out.println("==============="); new MyInterface() {
@Override public void methodAbs() { System.out.println("匿名内部类覆盖重写了方法"); }
@Override public void method() { System.out.println("匿名内部类覆盖重写了方法"); } }.methodAbs(); new MyInterface() { @Override public void methodAbs() { System.out.println("匿名内部类覆盖重写了方法"); }
@Override public void method() { System.out.println("匿名内部类覆盖重写了方法"); } }.method(); }
|
5. 类以及接口作为成员变量
Skill.java
1 2 3
| public interface Skill { void useSkill(); }
|
SkillImpl.java
1 2 3 4 5 6 7 8
| public class SkillImpl implements Skill {
@Override public void useSkill() { System.out.println("释放技能:国士无双"); }
}
|
Weapon.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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; } }
|
Hero.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| public class Hero { private String name; private int age; private Weapon weapon; private Skill skill;
public Hero() { }
public Hero(String name, int age, Weapon weapon,Skill skill) { this.name = name; this.age = age; this.weapon = weapon; this.skill=skill; }
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 Skill getSkill() { return skill; }
public void setSkill(Skill skill) { this.skill = skill; } public void attack() { System.out.println("英雄"); System.out.println("年龄:"+this.getAge()+" 名称:"+this.getName()+" 武器:"+this.getWeapon().getCode()); this.getSkill().useSkill(); System.out.println("Attack enemy!"); }
}
|
Main.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public class Demo06Main { public static void main(String[] args) { Hero hero =new Hero(); hero.setName("韩信"); hero.setAge(20); Weapon weapon =new Weapon(); weapon.setCode("枪"); hero.setWeapon(weapon); hero.setSkill(new SkillImpl()); hero.setSkill(new Skill() { @Override public void useSkill() { System.out.println("释放技能:背水一战"); } }); hero.attack(); } }
|