本文我们来学习什么是内部类,关于内部类的分类,以及内部类的使用特征。
在java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类,与之对应,包含内部类的类被称为外部类。
为什么要将一个类定义在另一个类里面呢?内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类,更好的实现了信息隐藏。
内部类的分类:成员内部类 静态内部类 方法内部类 匿名内部类
1)成员内部类:
内部类中最常见的就是成员内部类,也成为普通内部类
总结说来,具有以下特性。
* 1.内部类在外部使用时,无法直接实例化,需要借由外部类信息才能完成实例化
* 2.内部类的访问修饰符,可以任意,但是访问范围会受到影响。
* 3.内部类可以直接访问外部类的成员;如果出现同名属性,优先访问内部类中定义的
* 4.可以使用外部类.this.成员的方式,访问外部类中同名的信息
* 5.外部类访问内部类信息,需要通过内部类实例,无法直接访问
* 6.内部类编译后.class文件命名:外部类&内部类.class
* 7.内部类中是否可以包含与外部类相同方法签名的方法。
我们看以下代码:
package com.test;
//外部类:人
public class Person {
int age;
//获取内部类的方法
public Heart getHeart() {
new Heart().temp = 13; //访问内部类成员属性的方法
return new Heart();
}
public void eat() {
System.out.println("吃东西");
}
//成员内部类:心脏
class Heart{
int temp = 10;
public String beat() {
eat();
// return age + "心脏跳动";
return Person.this.age +"心脏跳动"; //同上面一样的效果
}
}
}
以下是测试类:
package com.test;
public class Test {
public static void main(String[] args) {
Person xx = new Person();
xx.age = 12;
//获取内部类实例对象:
//方式1:new 外部类.new 内部类
Person.Heart myHeart = new Person().new Heart();
System.out.println(myHeart.beat());
//方式2:外部类对象.new 内部类
Person.Heart myHeart2 = xx.new Heart();
System.out.println(myHeart2.beat());
//方式3:外部类对象.获取方法(一般情况下都会有一个获取内部类对象的方法)
Person.Heart myHeart3 = xx.getHeart();
System.out.println(myHeart3.beat());
/**
* 控制台输出:
* 吃东西
0心脏跳动
吃东西
12心脏跳动
吃东西
12心脏跳动
*
*/
}
}
2)静态内部类
静态内部类对象可以不依赖于外部类对象,直接创建。
以上是关于成员内部类的相关特征,实际上将成员内部类用static修饰,此时就变成了静态内部类,那么静态内部类有何特征呢?
总结说来,具有以下特性。
* 1、静态内部类中,只能直接访问外部类的静态成员,如果需要调用非静态成员,可以通过对象实例
* 2、静态内部类对象实例时,可以不依赖于外部类对象
* 3、可以通过外部类.内部类.静态成员的方式,访问内部类中的静态成员
* 4、当内部类属性与外部类属性同名时,默认直接调用内部类中的成员;
* 如果需要访问外部类中的静态属性,则可以通过 外部类.属性 的方式;
* 如果需要访问外部类中的非静态属性,则可以通过 new 外部类().属性的方式;
下面我们来看以下代码:
将Heart类定义在了Person类里面,且用static修饰,包含了一个静态属性age,静态方法say
public static class Heart {
public static int age = 13;
int temp = 22;
public static void say() {
System.out.println("hello");
}
//public void eat() {
// }
public String beat() {
//new Person().eat();
return Person.age + "岁的心脏在跳动";
}
}
以下是测试类:
package com.test;
public class Test {
public static void main(String[] args) {
//获取静态内部类对象实例
Person.Heart myHeart=new Person.Heart();
System.out.println(myHeart.beat());
Person.Heart.say();
}
3)方法内部类
定义在外部类方法中的内部类,也称局部内部类
总结说来,具有以下特性。
* 1、定义在方法内部,作用范围也在方法内
* 2、和方法内部成员使用规则一样,class前面不可以添加public、private、protected、static
* 3、类中不能包含静态成员
* 4、类中可以包含final、abstract修饰的成员
我们来看以下代码:
//外部类
public class Person {
public static int age;
public Object getHeart() {
class Heart {
public final int age = 13;
int temp = 22;
public final void say() {
System.out.println("hello");
}
public String beat() {
return Person.age + "岁的心脏在跳动";
}
}
return new Heart().beat();
}
}
以下是测试类:
public class PeopleTest {
public static void main(String[] args) {
Person lili=new Person();
lili.age=12;
System.out.println(lili.getHeart());
//输出:12岁的心脏在跳动
}
}
4)匿名内部类
就是没有名字的内部类,正因为没有名字,所以匿名内部类只能使用一次。我们将类的定义与类的创建,放到一起完成,它通常用来简化代码编写。但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口
适用场景:
-只用到类的一个实例
-类在定义后马上用到
-给类命名并不会导致代码更容易被理解
总结说来,具有以下特性。
* 1、匿名内部类没有类型名称、实例对象名称
* 2、编译后的文件命名:外部类$数字.class
* 3、无法使用private、public、protected、abstract、static修饰
* 4、无法编写构造方法,可以添加构造代码块
* 5、不能出现静态成员
下面我们来看以下代码:
1)抽象父类 Person, 拥有阅读的抽象方法。
public abstract class Person {
private String name;
public Person(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract void read();
}
2) 写两个类,Man,和Woman,继承自Person类。分别实现其不同的read方法。
方案1:见如下代码
方案2:使用到我们上文学到的多态知识,也能实现功能。
方案3:使用到本节我们需要学习的匿名内部类。
public class PersonTest {
//根据传入的不同的人的类型,调用对应的read方法
//方案1:
// public void getRead(Man man){
// man.read();
// }
// public void getRead(Woman woman){
// woman.read();
// }
//方案2:
public void getRead(Person person){
person.read();
}
public static void main(String[] args) {
PersonTest test=new PersonTest();
// Man one=new Man(); 方案2
// Woman two=new Woman();
// test.getRead(one);
// test.getRead(two);
//方案3:匿名内部类
test.getRead(new Person(){
{
//构造代码块
}
// public static int age=12; 不允许出现static,报错!
@Override
public void read() {
// TODO Auto-generated method stub
System.out.println("男生喜欢看科幻类书籍");
}
});
test.getRead(new Person(){
@Override
public void read() {
// TODO Auto-generated method stub
System.out.println("女生喜欢读言情小说");
}
});
}
}
注:匿名内部类初始化
我们一般都是利用构造器来完成某个实例的初始化工作的,但是匿名内部类是没有构造器的,那怎么来初始化匿名内部类呢?使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果。