目录
Java 内部类
内部类的概念及特点
将一个类定义置入另一个类定义中,这就叫作“内部类” 。
- 内部类之外的类称为外部类 。外部类无法为static。只允许public、abstract和final修饰符。
- 内部类的名称必须区别于它所在的外部类,和其它类之间没有要求 。
package neibulei;
public class D01 { // 内部类的全名叫做[外部类名称$内部类名称]
class D01{} //语法报错
public class B1 {}//语法正确,默认编译的结果名称为A1$B1.class
interface B{}//内部接口也ok
}
class B1 {}//其他类
- 内部类可以访问其外部类的所有变量和方法 。内部类被当成外部类的成员。
package neibulei;
public class D02 { //外部类的范围限定词只能是public或者默认package
private int a = 0;
public void yuan() {
}
private class A{内部类的范围限定词可以是4种
public void yuan() {//方法和外部类同名也没关系
System.out.println(a);//可直接访问外部类的成员
System.out.println(D02.this.a);//D02.this指的是D02的一个对象
this.yuan();//调用的本类方法,不加this.也是本类方法
D02.this.yuan();//调用的外部类D02方法
}
}
}
- 外部类不能直接访问内部类的实现细节,可以通过创建内部类对象的方式直接访问,不受限定词的影响 。
package neibulei;
public class D02 { // 外部类的范围限定词只能是public或者默认package
private int a = 0;
public void yuan() {
}
private class A { // 内部类的范围限定词可以是4种
public void yuan() { // 方法和外部类同名也没关系
System.out.println(a); // 可直接访问外部类的成员
System.out.println(D02.this.a);// D02.this指的是D02的一个对象
this.yuan(); // 调用的本类方法,不加this.也是本类方法
D02.this.yuan(); // 调用的外部类D02方法
}
private String a = "zxyhan"; // 内部类的属性
private void aaa() { // 内部类的方法
}
}
public static void main(String[] args) {
D02 d = new D02();
A a = d.new A(); //必须要外部类的实例才能new内部类对象
a.aaa(); //调用内部类私有方法
System.out.println(a.a); //调用内部类私有属性
d.dd(); 调用本类方法
}
public void dd() {
A a = new A(); //不需要外部类实例直接new内部类对象
a.aaa(); //调用内部类私有方法
System.out.println(a.a); //调用内部类私有属性
}
}
- 内部类比外部类多了private/protected/static三个修饰符,这三个修饰符不能用在外部类上 。
- 非静态内部类不能拥有静态成员,静态内部类则没有这个限制 。
package neibulei;
public class D03 {
private int aa = 100;
public static class DD{ //静态类,可以直接类名调用属性方法
private static int a = 10; //静态内部类可以有静态成员
static { //可以有静态代码块
}
public static void main(String[]args ){//可以有静态方法
System.out.println(a);
D03 sd = new D03();
DD.DDd();//静态类,可以直接类名调用属性方法
DD ss = new DD();
ss.asd();// 对象调用方法
System.out.println(sd.aa); //非静态属性 需要对象调用
}
public DD(){//定义构造方法
}
public static void DDd() {//静态方法
System.out.println("调用静态方法DDd");
}
public void asd(){ //非静态方法
System.out.println("调用非静态方法asd");
}
}
}
内部类的作用
- 内部类提供更好的封装。
- 内部类可以直接访问外部类的私有成员,外部类不能直接访问内部类的成员 。
- 匿名内部类适合用于创建仅仅使用一次使用的类。
内部类相关的设计
- 分析事物时发现该事物描述还有事物,而且这个事物还在访问被描述事物的内容例如牛和牛腿 。
- 如果一个事物离开另外一个事物后则没有任何意义,这种情况下建议使用内部类,不允许其他类访问 。
- 内部类能直接访问外部类中成员,是因为内部类持有了外部类的引用,即外部类名.this 。
内部类分类
在
Java
中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一
般来说包括这四种:
成员内部类、局部内部类、匿名内部类和静态内部类。
内部类实际拥有外部类的一个引用。
非静态内部类
- 在创建非静态内部类对象时,一定要先创建起相应的外部类对象 。
package neibulei;
public class D04 {
public static void main(String[] args) {
DY aa = new DY();
DY.n1 cc = aa.new n1(); //内部类的写法为[外部类名.内部类名],否则需要import com.yan.B1.C1;则可以直接使用C1类。至于C1类是否可见取决于C1类的范围限定词
System.out.println(cc.a); //public 属性所以可以调用 输出结果:10
System.out.println(cc); //直接输出一个类的对象 结果是:neibulei.DY$n1@15db9742
}
}
class DY { //外部类
public class n1 { // 非静态内部类如果是private则new不了n1对象
public int a = 10;
}
}
- 在任何非静态内部类中,都不能有静态数据、静态方法或者又一个静态内部类。
- 注意内部类的可见性范围限制 。
- 访问方法:直接访问外部类中内部类中的成员 。
- 外部类.内部类 in=new 外部类().new 内部类(); 。
- 创建外部类对象和内部类无关,创建外部类对象并不会自动创建内部类对象
静态内部类
- 静态内部类中,可以有静态数据、静态方法或者又一个静态内部类 。
- 静态内部类中,也可以有非静态数据、非静态方法或者又一个非静态内部类 。
- 静态内部类中,不能访问外部类的非静态成员,这是由Java语法中【静态方法不能直接访问非静态成员】所限定 。
package neibulei;
public class D05 {
public static void main(String[] args) {
Bb1.C1 cc = new Bb1.C1();// 不需要构建外部类对象,就可以直接创建静态内部类对象,但是是 否可见取决于范围限定词
Bb1.C1.pp();// 可以直接访问静态内部类中的静态成员,但是是否可见取决于范围限定词
cc.ff();
}
}
class Bb1 {
static class C1 {// 在静态内部类中才可以定义静态成员
private static int age = 123;
private String pwd = "123456";// 同时允许定义非静态成员
static { // 静态代码块
System.out.println("c1 static...");
}
public static void pp() {// 静态方法
System.out.println("c1 static pp...");
}
public void ff() {// 同时允许定义非静态成员
}
static class D1 {
}// 定义静态类
class E1 {
}// 同时允许定义非静态类
}
}
局部内部类
可以将内部类定义在一个方法或者一个代码块内
注意:局部内部类需要先定义后使用!
package neibulei;
public class D06 {
public int a = 1;
public static void main(String[] args) {
D06 dy = new D06();
dy.yuan();
}
public void yuan(){
// Dd bb=new Dd();语法错误,要求局部内部类必须先定义后使用
class Dd{ // 局部内部类,只能在所在的{}范围中使用,具备内部类的范围限定词和临时变量一致, 只能添加final或者abstract
public void ff() {
System.out.println("局部内部类输出!"+a);
D06.this.a = 555;// 可以直接访问外部类中的成员
}
}
Dd bb=new Dd(); //在方法里new局部类对象
bb.ff(); //在方法里调用局部类方法
}
}
输出结果:局部内部类输出!1
匿名内部类
仅使用一次
匿名内部类可以使你的代码更加简洁,你可以在定义一个类的同时对其进行实例化。它与局部类很相似,不同的是它没有类名,如果某个局部类你只需要用一次,那么你就可以使用匿名内部类。
匿名内部类就是内部类的简写格式 。
package neibulei;
public class D07 {
public void SS() {
System.out.println(" D07的SS方法!");
}
public static void main(String[] args) {
new D07().SS();// new 一个D07对象调用D07类的方法
new D07() { // 内部类体
public int aa = 10;
public void SS() {
System.out.println("匿名内部类属性" + aa);
System.out.println("匿名内部类的SS方法!");
}
}.SS();// 这就相当于这个匿名类继承了D07并且被实例化然后调用方法,只用这一次!
}
}
匿名内部类的前提是必须继承或者实现一个外部类或者接口。
new
interfacename
(){...匿名内部类...};
new
superclassname
(){...匿名内部类...};
匿名内部类由于没有名字,所以它没有构造函数 ;
如果这个匿名内部类继承了一个只含有带参数构造函数的父类,创建它的时候必须带上这些参数 ;
不能定义静态成员;
匿名内部类的接口使用场景
package neibulei;
public interface D08 {//D08接口规范
public void zxy();
public int ddy();
public String an();
}
package neibulei;
public class D09 {
public static void main(String[] args) {
DA a = new DA();
a.zxy(new DB());//括号要放的是实现接口的类对象
a.zxy(new D08() {//内部类要实现接口就要实现接口里的所有方法。
public void zxy() {
System.out.println("打印zxy方法");
}
public int ddy() {
return 0;
}
public String an() {
return null;
}
}); //相当于new了一个实现接口的内部类的对象
a.ddd(null);//括号放字符串类
a.ddd(new D08() {//内部类调用an方法返回了String类
public void zxy() {
}
public int ddy() {
return 0;
}
public String an() {
return "dsdsg";
}
}.an());
}
}
class DA{
public void zxy(D08 a) {
System.out.println("打印DA类的zxy方法!");
}
public void ddd(String a) {
System.out.println("打印DA类的ddd方法!"+a);
}
}
class DB implements D08{
public void zxy() {
}
public int ddy() {
return 0;
}
public String an() {
return null;
}
}
输出结果:
打印DA类的zxy方法!
打印DA类的zxy方法!
打印DA类的ddd方法!null
打印DA类的ddd方法!dsdsg
内部类的使用场景和好处
- 每个内部类都能独立的提供一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整。
- 方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。
- 方便编写事件驱动程序 。
btn.addActionListener(new ActionListener() {//添加按钮对应的事件处理
public void actionPerformed(ActionEvent e) {
showNewWindow(mainWin);
}
});
- 方便编写线程代码。