成员内部类
简单概述
简而言之就是定义在一个类内部的类
接下来讲点注意点,就举例子理解
1、方法内部不能定义方法,但类的内部可以再次定义类
2、包含类的特点,但也有成员属性的限制
3、外部类的修饰符只有 [public、默认的],但内部类的修饰限定符和成员属性一样,比如static、final
接下来详细的使用方法都会在代码中举例、注释
代码举例讲解
package 内部类;
/*
整理理解的话,内部类就是
类+类成员属性
既满足类的含有的功能
也满足成员属性的一些限制,比如修饰符;静态、非静态的访问;变量的就近原则...
*/
public class Outer {
private int num = 10;
static int age = 20;
public class Inner{
/*
内部类注意点:
1、访问修饰符和成员变量成员方法一样
2、也可以用static修饰
3、但同样满足静态不能访问非静态,非静态可以访问静态,前面讲过
4、非静态内部类不能定义静态方法和变量
5、内部类可以访问外部类元素
*/
private int age;
private int num;
public void methodInner(){
System.out.println("这是内部类方法");
System.out.println(num);//优先访问靠近的,都是一样的
System.out.println(age);
//成员与方法的调用一样
System.out.println(this.age);//指的是内部类的变量
System.out.println(Outer.this.num);//是外部类的变量
System.out.println(Outer.age);//非静态成员可以访问静态成员
}
}
//内部类之间的继承,
// 当然接口的继承都是可以的,对于其他类、外部类(没必要,本来就可以访问外部类元素)都是可以继承的
//抽象类、接口哪些就不一一举例了,基本都是一样的
public class SubInner extends Inner{
@Override//重写,都是满足类的功能的
public void methodInner() {
super.methodInner();
}
}
public void method1(){
//这里可以创建内部类,但是静态方法,就不能创建非静态内部类,可以考虑内存的加载
//但静态方法可以通过创建外部类来创建内部类,即主方法的演示
System.out.println("这是外部类方法");
Inner inner = new Inner();//可以创建内部类成员、用内部类成员调用相应数据
inner.methodInner();
}
public static void main(String[] args) {
Outer test1 = new Outer();
test1.method1();
//如果想要创建内部类对象
//静态访问非静态,需要借用外部类
Outer.Inner inner = test1.new Inner();
//如果访问别的类中的静态内部类Outer.Inner inner = new Outer.Inner();
//访问别的类中的非静态内部类Outer.Inner inner = outer.new Inner();
//如果内部类是静态的可以这样创建内部类:Inner inner = new Inner();静态之间是可以直接访问的
inner.methodInner();
}
}
浅谈内部类
根据上面知识点总结一下
非静态内部类的特点
在非静态内部类中不能定义static修饰的属性,方法,代码块。
在非静态内部类中可以调用外部类的属性,方法。
在非静态内部类的方法中可以调用外部类的属性,方法,满足就近原则。
如果出现同名?怎么区分?外部类的属性或方法外部类的名 . this.属性|方法();
可以访间外部类static修饰的属性或方法吗?可以的
如何调用非静态内部的属性或方法呢?
1)在外部类的中进行?
外部类非静态方法:直接创建内部类的对象,然后通过对象进行调用属性或方法
外部类静态方法:创建外部类的对象,再根据外部类对象.new 内部类()语法创建内部类对象通过内部类对象调用属性和方法
2)在其他的类中如何调用?
创建外部类的对象,再根据外部类对象. new内部类()语法创建内部类对象通过内部类对象调用属性和方法
静态内部类的特点
static修饰的,可以再静态内部类中使用static关键字来修饰属性和方法,以及代码块。
再静态内部类中,只能调用外部类中静态的属性和方法。在静态内部类中不能使用外部类名 . this
再静态内部类中不能使用this关键字?
错误的,再静态内部类中可以定义非静态的方法。可以再非静态方法中使用this关键字,调用该静态内部类中定义的非静态属性和方法。但是不能使用外部类 . this
如果想调用静态内部类中的属性和方法:
如果是静态成员,可以直接通过静态内部类名,进行调用, 如果再其 他类中可以通过外部类.内部类.静态成员
如果是非静态成员,必须得创建静态内部类的对象通过对象名。进行调用:外部类.内部类对象名= new 外部类 .内部类();
注意:内部类可以创建对象也是因为在内部类中有构造方法。如果显示添加带参构造方法,new对象的时候,必须传递参数。
基本了解了之后,我们研究一下内部类的好处。要我说也就是解决的java中单继承的弊端,每一个内部类都可以独自继承一个类、接口、抽象类,这样就可以丰富类的功能,但说的很不专业,还是在上一下专业术语。
为什么要使用内部类?在《Think in java》中有这样一句话:使用内部类最吸引人的原因是:每个 内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实 现,对于内部类都没有影响。 在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个 时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问 题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。使 用内部类最大的优点就在于它能够非常好的解决多重继承的问题,但是如果我们不需要解决多重继 承问题,那么我们自然可以使用其他的编码方式,但是使用内部类还能够为我们带来如下特性(摘 自《Think in java》):
1、内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独 立。
2、在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
3、创建内部类对象的时刻并不依赖于外围类对象的创建。
4、内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
5、内部类提供了更好的封装,除了该外围类,其他类都不能访问。
成员内部类也是最普通的内部类,它是外围类的一个成员,所以他是可以无限制的访问外围类的所 有 成员属性和方法,尽管是private的,但是外围类要访问内部类的成员属性和方法则需要通过内 部类实例来访问.
局部内部类
初步理解
基本一样,这里只提一下不同点
1、定义在代码块中,只有在代码块中有效,和局部变量一样
2、没有访问修饰符,没有static,和局部变量是一样的
3、相关特性和局部变量一致,也包含类的属性
4、局部内部类无法访问同名局部变量
代码理解
package 内部类;
public class Part {
{
class inner1{
}
}
int age = 44;
static int name = 33;
static {
int name = 22;
class inner2{
public int name = 12;
int age = 13;
public void test(){
System.out.println(name);
System.out.println();//局部内部类无法访问同名局部变量
System.out.println(Part.name);
// System.out.println(Part.this.age);
//System.out.println(Part.age);静态不能访问非静态
}
}
inner2 i = new inner2();
i.test();
}
public void f(){
class inner3{
}
}
public static void main(String[] args) {
class inner4{
}
}
}
总结
局部内部类:
位置在方法中,代码块中,构造方法中。作用范围也只能在声明他的语句块中。
局部内部类不能用访问修饰符修饰,也不能用static修饰。所以局部 内部类中定义的属性和方法以及代码块是非静态的。
局部内部类可以访问外部类中声明的属性和方法。[看局部内部类所在的块是否是静态决定能够访问哪些成员]
如果使用?创建局部内部类的对象,通过局部内部类对象名。进行访问.
局部内部类的方法可以访问所在的块声明的局部变量,在jdk1 .7前该变量必须是final修饰的,但是jdk8后不要求了。
匿名内部类
匿名类,就是没有名称的类,其名称由Java编译器给出,一般是形如:外部类名称+$+匿名类顺 序,没有名称也就是其他地方就不能引用,不能实例化,只用一次,当然也就不能有构造器。 匿名类根据位于地方不同分为:成员匿名类和局部匿名类。
匿名类不能使用任何关键字和访问控制符,匿名类和局部类访问规则一样,只不过内部类显式的定 义了一个类,然后通过new的方式创建这个局部类实例,而匿名类直接new一个类实例,没有定义 这个类。匿名类最常见的方式就是回调模式的使用,通过默认实现一个接口创建一个匿名类然后, 然后new这个匿名类的实例。
代码讲解
先写一个接口
package 内部类;
public interface Inter {
public void f();
}
匿名内部类的实现
package 内部类;
public class Test {
public void test(Inter inter){//传进来的接口并没有实现
inter.f();
}
public static void main(String[] args) {
Test t = new Test();
//方法一:只是用一次
t.test(new Inter() {
@Override
public void f() {
System.out.println("测试");
}
});
//方法二:可以多次使用,所以接口没有实现的话,这种方法也是可以使用的
Inter inter = new Inter() {
@Override
public void f() {
System.out.println("测试");
}
};
t.test(inter);
}
}