为什么有内部类?
因为类的设计需要,比方说:我们现在要设计一个 宠物鸟类;那么这个类需要设计在 鸟笼类内部;这样内部类可以方便的访问到外部类的实例属性,比如主人给的鸟食,水等(想想如果放在外部,还需要先new一个鸟笼对象才行)。
一个最简单的内部类
class Outter{
private int a=1;
// 内部类
class Inner{
}
}
内部类与其外部类的访问规则
我们都知道,对于外部类,修饰符只有 public / 无 / Abstract / final。
但是对于内部类来说,它处于外部类的成员位置,可以用任何成员修饰符修饰:private / 无 / protected /public/ fianl / static等。
- 对于不加修饰的内部类,可从外部以 new Outter().new Inner() 直接访问
- 内部类可以直接访问其外部类成员
- 对于静态的内部类,外部可以以 new Outter.Inner() 取得这个内部类
- 当内部类中含有静态成员或方法时,必须用静态修饰该内部类。
class Outter{
private int a=1;
// 外部类访问内部类属性需要new一个内部类对象
public void printB() {
Inner inner = new Inner();
System.out.println(inner.b);
}
// 内部类
class Inner{
int b=2;
// 内部类可直接访问其外部类的属性
void printA() {
System.out.println(a);
}
}
}
public class Main {
public static void main(String[] args) {
Outter outter = new Outter();
//测试外部类访问内部类的属性
outter.printB();
// 当内部类被private修饰时,仅其所在的外部类可访问
// 当内部类无任何修饰时,内部类可被 同一包下的任何类访问
// Inner inner = new Inner(); 不行,
Outter.Inner inner = new Outter().new Inner();
inner.printA();
}
}
package bag1;
class Outter{
private int a=1;
static String c = "Outter static var";
// 外部类访问内部类属性需要new一个内部类对象
/** 内部类变成静态的
说明内部类不依赖外部类产生
访问内部类:Outter.Inner inner = new Outter.Inner();
*/
static class Inner{
static String x= "static inner var";
int b=2;
void printB() {
System.out.println(b);
}
void printC() {
System.out.println(c);
}
}
}
public class Main {
public static void main(String[] args) {
//测试外部类访问静态内部类的属性
Outter.Inner inner = new Outter.Inner();
inner.printB();
// 测试外部类访问静态内部类的静态属性
System.out.println(Outter.Inner.x);
// 测试静态内部类只能访问其外部类的静态属性
inner.printC();
}
}
package bag1;
class Outter{
private int a=1;
class Inner{
int a = 2;
void visitA() {
int a = 3;
// 同名时这样访问外部类
System.out.println(Outter.this.a);
}
}
}
public class Main {
public static void main(String[] args) {
new Outter().new Inner().visitA();
}
}
匿名内部类
当内部类放在局部;访问局部变量时,这个局部变量必须用final修饰;jdk8以后就不用了。编译器自动加。
package bag1;
class Outter{
private int a=1;
void method() {
// 本来这个是必须用final修饰
// 才能被内部类访问的;因为如果存在这样一种情况
// 方法返回一个内部类对象,对象中又有对方法局部变量的引用
// 方法运行完,局部变量会消失;所以必须加final
// 但是jdk8以后就不用加了,编译器自动加
//
int c = 3;
//方法内的内部类还是可以访问其外部类成员
class Inner{
private int b = 2;
void show() {
System.out.println("内部类访问外部类属性: "+a+" 内部类属性:"+b
+"局部内部类访问方法内的局部变量"+c);
}
}
Inner inner = new Inner();
inner.show();
}
}
public class Main {
public static void main(String[] args) {
new Outter().method();
}
}
将上面的内部类改成匿名内部类
1. 先有一个外部的接口或抽象类;
2. 不用在外部类定义内部类,而是在需要用到内部类的时候直接new
package bag1;
// 为匿名内部类提供接口的抽象类
abstract class Inn{
abstract void show();
}
class Outter{
private int a=1;
void method() {
// 创建匿名内部类
new Inn()
{
void show(){
System.out.println("我是匿名内部类");
}
}.show(); // 调用此匿名类的方法
}
}
public class Main {
public static void main(String[] args) {
new Outter().method();
}
}
给匿名内部类加上引用,从而可以调用多个匿名内部类方法,(注意,这里的匿名是指 new 后面的 { }是没有名字的。)
package bag1;
// 为匿名内部类提供接口的抽象类
abstract class Inn{
abstract void show();
}
class Outter{
private int a=1;
void method() {
// 创建匿名内部类
Inn in = new Inn()
{
void show(){
System.out.println("我是匿名内部类");
}
};
// 调用此匿名类的方法
in.show();
}
}
public class Main {
public static void main(String[] args) {
new Outter().method();
}
}
匿名内部类使用最多的场景
package bag1;
// 为匿名内部类提供接口的抽象类
abstract class Inn{
abstract void show();
}
class InnImpl extends Inn {
@Override
void show() {
System.out.println("实现抽象类的方法");
}
}
class Outter{
// 接口作为参数传入时
void method1(Inn in) {
in.show();
}
// 创建匿名内部类 代替上述的表述
void method2() {
Inn in = new Inn()
{
void show(){
System.out.println("我是匿名内部类实现的抽象类的方法");
}
};
// 调用此匿名类的方法
in.show();
}
}
public class Main {
public static void main(String[] args) {
Outter out = new Outter();
out.method1(new InnImpl());
out.method2();
}
}
使用内部类一个需要注意的地方
package bag1;
// 为匿名内部类提供接口的抽象类
abstract class Inn{
abstract void show();
}
class Outter{
void method1() {
// 这样调用 show2 可行
new Inn()
{
void show(){
System.out.println("方法一");
}
void show2() {
System.out.println("方法二");
}
}.show2();
}
void method2() {
Inn in = new Inn()
{
void show(){
System.out.println("方法一");
}
void show2() {
System.out.println("方法二");
}
};
// 因为抽象类不存在show2;所以向上转型的 匿名类无法调用
//in.show2();
}
}
public class Main {
public static void main(String[] args) {
Outter out = new Outter();
out.method1();
}
}