内部类:类的第五个成员
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。
1.定义
Java中允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。
2.内部类的分类
成员内部类(静态、非静态 ) vs 局部内部类(方法内、代码块内、构造器内)
如:
package com.my.java2;
public class InnerClassTest {
}
class Person{
//静态成员内部类
static class Police{
}
//非静态成员内部类
class FireMan{
}
public void method() {
//局部内部类
class Aa{
}
}
//代码块
{
//局部内部类
class Bb{
}
}
//构造函数
public Person() {
//局部内部类
class Cc{
}
}
}
3.成员内部类的理解
3.1作为一个类
3.1.1类内可以定义属性、方法、构造器等
package com.my.java2;
public class InnerClassTest {
}
class Person{
//静态成员内部类
static class Police{
//属性
String name;
int age;
//构造器
public Police(){
}
//方法
public void show(){
System.out.println("站军姿");
}
}
//非静态成员内部类
class FireMan{
//属性
String name = "001";
//构造器
public FireMan(){
}
//方法
public void train(){
System.out.println("5公里越野!");
}
}
public void method() {
//局部内部类
class Aa{
}
}
//代码块
{
//局部内部类
class Bb{
}
}
//构造函数
public Person() {
//局部内部类
class Cc{
}
}
}
3.1.2可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
package com.my.java2;
public class InnerClassTest {
}
class Person{
//非静态成员内部类
final class FireMan{
//属性
String name = "001";
//构造器
public FireMan(){
}
//方法
public void train(){
System.out.println("5公里越野!");
}
}
}
3.1.3可以被abstract修饰
package com.my.java2;
public class InnerClassTest {
}
class Person{
//静态成员内部类
abstract static class Police{
//属性
String name;
int age;
//构造器
public Police(){
}
//方法
public void show(){
System.out.println("站军姿");
}
}
}
3.2作为外部类的成员
3.2.1调用外部类的结构
package com.my.java2;
public class InnerClassTest {
}
class Person{
public void eat(){
System.out.println("吃菠萝蜜");
}
//非静态成员内部类
class FireMan{
//属性
String name = "001";
//构造器
public FireMan(){
}
//方法
public void train(){
System.out.println("5公里越野!");
//调用外部类的非静态属性
Person.this.eat();//这里的Person.this可以省略直接eat();也可以的
}
}
}
3.2.2可以被static修饰
package com.my.java2;
public class InnerClassTest {
}
class Person{
public void eat(){
System.out.println("吃菠萝蜜");
}
//静态成员内部类
static class Police{
//属性
String name;
int age;
//构造器
public Police(){
}
//方法
public void show(){
System.out.println("站军姿");
}
}
}
3.2.3可以被4种不同的权限修饰
package com.my.java2;
public class InnerClassTest {
}
class Person{
public void eat(){
System.out.println("吃菠萝蜜");
}
//非静态成员内部类
private class FireMan{
//属性
String name = "001";
//构造器
public FireMan(){
}
//方法
public void train(){
System.out.println("5公里越野!");
//调用外部类的非静态属性
Person.this.eat();//这里的Person.this可以省略直接eat();也可以的
}
}
//非静态成员内部类
class FireMan2{
//属性
String name = "001";
//构造器
public FireMan2(){
}
//方法
public void train(){
System.out.println("5公里越野!");
//调用外部类的非静态属性
Person.this.eat();//这里的Person.this可以省略直接eat();也可以的
}
}
//非静态成员内部类
protected class FireMan3{
//属性
String name = "001";
//构造器
public FireMan3(){
}
//方法
public void train(){
System.out.println("5公里越野!");
//调用外部类的非静态属性
Person.this.eat();//这里的Person.this可以省略直接eat();也可以的
}
}
//非静态成员内部类
public final class FireMan4{
//属性
String name = "001";
//构造器
public FireMan4(){
}
//方法
public void train(){
System.out.println("5公里越野!");
//调用外部类的非静态属性
Person.this.eat();//这里的Person.this可以省略直接eat();也可以的
}
}
}
4.关注如下的3个问题
4.1如何实例化成员内部类的对象
package com.my.java2;
public class InnerClassTest {
public static void main(String[] args) {
//创建Police实例(静态的成员内部类)
Person.Police police = new Person.Police();
police.show();
//创建FireMan实例(非静态的成员内部类)
Person p = new Person();
Person.FireMan fireman = p.new FireMan();
fireman.train();
}
}
class Person{
public void eat(){
System.out.println("吃菠萝蜜");
}
//静态成员内部类
static class Police{
//属性
String name;
int age;
//构造器
public Police(){
}
//方法
public void show(){
System.out.println("站军姿");
}
}
//非静态成员内部类
class FireMan{
//属性
String name = "001";
//构造器
public FireMan(){
}
//方法
public void train(){
System.out.println("5公里越野!");
//调用外部类的非静态属性
Person.this.eat();//这里的Person.this可以省略直接eat();也可以的
}
}
}
4.2 如何在成员内部 类中区分调用外部类的结构
package com.my.java2;
public class InnerClassTest {
public static void main(String[] args) {
//创建FireMan实例(非静态的成员内部类)
Person p = new Person();
Person.FireMan fireman = p.new FireMan();
// fireman.train();
fireman.display("水娃");
}
}
class Person{
String name = "诸葛亮";
public void eat(){
System.out.println("吃菠萝蜜");
}
//非静态成员内部类
class FireMan{
//属性
String name = "001";
//构造器
public FireMan(){
}
//方法
public void train(){
System.out.println("5公里越野!");
//调用外部类的非静态属性
Person.this.eat();//这里的Person.this可以省略直接eat();也可以的
}
public void display(String name) {
System.out.println(name);//方法的形参
System.out.println(this.name);//内部类的属性
System.out.println(Person.this.name);//外部类的属性
}
}
}
4.3 开发中局部内部类的使用
package com.my.java2;
public class InnerClassTest1 {
//开发中很少见
public void method() {
//局部内部类
class Aa{
}
}
//返回一个实现了Comparable接口的类的对象
public Comparable getComparable() {
//创建一个实现了Comparable接口的类:局部内部类
//方法一:
// class MyComparable implements Comparable{
//
// @Override
// public int compareTo(Object o) {
// // TODO Auto-generated method stub
// return 0;
// }
//
// }
// return new MyComparable();
//方法二:匿名类
return new Comparable() {
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
return 0;
}
}
}
}
注意点
在局部内部类的方法中(比如:show如果调用局部内部类所声明的方法(比如:method)中的局部变量(比如:num)的话,要求此局部变量声明为final的。
jdk 7及之前版本:要求此局部变量显式的声明为final的
jdk 8及之后的版本:可以省略final的声明
package com.my.java2;
public class InnerClassTest {
public void method(){
//局部变量
int num = 10;
class AA{
public void show(){
// num = 20;//不能修改,因为num省略的final
System.out.println(num);
}
}
}
}
总结
成员内部类和局部内部类,在编译以后,都会生成字节码文件。
格式:成员内部类:外部类
内部类名
.
c
l
a
s
s
局部内部类:外部类
内部类名.class 局部内部类:外部类
内部类名.class局部内部类:外部类数字 内部类名.class