摘要
内部类?成员内部类?局部内部类?匿名内部类?类以及接口作为成员变量?
正文
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*/ {//这个地方表示所有的东西其实都是继承自Object
int num=20;//内部类的成员变量
public void methodInner(){
int num=30;//内部类的局部变量
System.out.println(num);//30
System.out.println(this.num);//20
System.out.println(Outer.this.num);//30
}
}
}
|
如果重现重名现象
外部类名称.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. 局部内部类的定义及其使用
如果一个类是定义在一个方法内部的,那么这就是一个局部内部类
局部:只有当前所属的方法才能使用他,出了这个方法外面就不能用了
定义格式:
修饰符 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);//10
}
}
//局部内部类,只有在这个范围内才能使用,所以,看下面
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;//所在方法的局部变量
//num=20;//如果再加上这一句,就会报错了,因为必须是有效final
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. 匿名内部类(属于局部内部类)的定义及其使用
如果接口的实现类,或者是父类的子类,只需要使用唯一的一次。
那么这种情况下,就可以省略该类的定义,而使用匿名内部类。
匿名内部类的定义格式:
接口名称 对象名 = new 接口名称(){
//覆盖重写接口中所有的抽象方法
}
new 接口名称()表示要继承的接口,后面的{}才是匿名内部类
对格式“new 接口名称(){...}”进行解析:
- new代表创建对象的动作
- 接口名称就是匿名内部类要实现的接口
- {...}才是匿名内部类的内容
注意:
- 匿名内部类,在创建对象的时候,只能使用唯一一次。
如果希望多次创建对象,而且类的内容一样的话,那么就必须使用单独定义的实现类了
- 匿名对象,在调用方法的时候,只能调用唯一一次
如果希望同一个对象,调用多次方法,那么必须给对象起名
- 匿名内部类是省略了实现类或者子类,匿名对象是省略了对象名称
强调:匿名内部类和匿名对象不是一回事
匿名内部类有对象名称,匿名对象没有
MyInterface.java
1
2
3
4
5
| public interface MyInterface {
void methodAbs();//抽象方法,隐藏了public abstract
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) {
//MyInterfaceImpl impl=new MyInterfaceImpl();
//MyInterface impl=new MyInterfaceImpl();//多态写法
//impl.methodAbs();
//可以使用匿名内部类写
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 weapon =new Weapon();
weapon.setCode("枪");
//为英雄配备武器
hero.setWeapon(weapon);
//设置技能:1.可以使用单独定义的实现类 2.可以使用匿名内部类
hero.setSkill(new SkillImpl());//使用单独定义的实现类
//还可以使用匿名内部类(下面使用的是匿名内部类和匿名对象)
hero.setSkill(new Skill() {
@Override
public void useSkill() {
System.out.println("释放技能:背水一战");
}
});
//英雄Attack
hero.attack();
}
}
|