内部类
成员内部类
成员内部类看起来像是外部类的一个成员,所以内部类可以拥有private、public等访问权限修饰符修饰;当然,也可以用static来修饰。成员内部类分为:
1.静态成员内部类:使⽤static修饰类
2.非静态成员内部类:未⽤static修饰类,在没有说明是静态成员内部类时,默认成员内部类指的就是非静态成员内部类;
注:只有成员内部类才能加static变成静态内部类。
静态成员内部类
使用static修饰的内部类我们称之为静态内部类,我们要知道只要是static修饰的类那它一定是内部类,不可能是外部类。静态内部类与非静态内部类之间存在一个最大的区别,非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围类的对象,但是静态内部类却没有。没有这个引用就意味着:
- 它的创建不需要依赖于外围类的对象
- 它不能使用任何外围类的非static的成员变量和方法(因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果使用外部类的非static成员就会发生矛盾,因为外部类的非static成员必须依附于具体的对象)
- 创建对象的方式:
外部类.内部类 变量名 = new 外部类.内部类();
public class Outer {
int c=4;
static class Inner {
int b = 3;
static void fun() {
System.out.println("123456");
}
void test02() {
System.out.println(c);//无法访问
}
}
}
class Test {
public static void main(String[] args) {
Outer.Inner inner=new Outer.Inner();
inner.test02();
}
}
非静态成员内部类
public class Outer {
private int c = 4;
int a = 4;
class Inner2 {
static int a = 3;
int c = 4;
void test() {
System.out.println(c); // 可以访问
System.out.println(Outer.this.a);
}
}
}
- 成员内部类访问外部类的信息
类Inner2像是类Outer的一个成员,Outer称为外部类。非静态成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括 private 成员和静态成员)。
注:当非静态成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量
或外部类.this.成员方法
- 创建非静态内部类对象
成员内部类是依附外部类而存在的,所以要创建成员内部类的对象,前提是必须存在一个外部类的对象。
public static void main(String[] args) {
Outer outer = new Outer();
Inner2 inner2 = outer.new Inner2();
}
- 外部类访问成员内部类信息
外部类也可以访问内部类的所有成员变量和方法(包括private),但外部类想访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问
public static void main(String[] args){
Outer outer = new Outer();
Inner2 inner2=outer.new Inner2();
System.out.println(inner2.c)
}
内部类的继承:
内部类和其他普通类一样,同样可以被继承,这样给本来就十分灵活的内部类增加了更好的结构性和代码复用性。只是内部类的继承和普通类有一些不同之处,是在使用时需要多加注意的。因为内部类在创建时需要外部类的引用,所以在内部类的继承上也需要外部类的协助。接下来看示例代码。
public class Inner3 extends Inner.Inner2{
Inner3(Inner inner){
inner.super();
}
public static void main(String[] args) {
Inner inner=new Inner();
Inner3 i3=new Inner3(inner);
}
}
首先在继承语句extends处,注意命名空间,需要加上外围类名,才能对应上正确的内部类。其次是构造对象上,这里需要自己写一个接受外围类引用的构造器,来给导出类提供创建对象的基本环境。注意在构造器中的这一句inner.super()
这是必须在构造器中使用的,才能够成功的构造出一个继承自内部类的对象。
案例
创建一个包含内部类的类,此内部类有一个非默认构造器(需要参数的构造器)。创建另一个也包含内部类的类,该类的内部类继承自第一个内部类。
public class Kfm {
class Ycdl{
String name;
Ycdl(String name){
this.name=name;
}
}
}
public class Sup {
class Sub extends Kfm.Ycdl{
Sub(Kfm kfm,String name){
kfm.super(name);
}
}
}
class Test2{
public static void main(String[] args) {
Kfm kfm=new Kfm();
Sup sup=new Sup();
Sup.Sub sub=sup.new Sub(kfm,"test");
}
}
既然说到了继承,很自然的就会联想到,内部类会被覆盖吗?
当一个外部类继承自另一个含有内部类的父类。然后在该类中重写了父类的内部类,这个时候会怎么样呢?父类的内部类会被覆盖吗?
class Egg{
private Yolk y;
protected class Yolk{
public Yolk(){
System.out.println("Egg.Yolk()");
}
}
public Egg(){
System.out.println("New Egg");
y = new Yolk();
}
}
public class BigEgg extends Egg{
public class Yolk{
public Yolk(){
System.out.println("BigEgg.Yolk");
}
}
BigEgg() {
System.out.println("new BigEgg");
Yolk y = new Yolk();
}
public static void main(String[] args){
BigEgg bigEgg = new BigEgg(); //
bigEgg.new Yolk();
}
}
//New Egg
//Egg.Yolk()
//new BigEgg
//BigEgg.Yolk
//BigEgg.Yolk
局部内部类:
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
public class Outer {
public void outerMethod() {
class LocalInner {
void innerMethod() {
System.out.println("Local inner class method");
}
}
LocalInner localInner = new LocalInner();
localInner.innerMethod();
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.outerMethod(); // 输出 "Local inner class method"
}
}
一个类可以有多个内部类,内部类可以实现接口和继承类,内部类可以解决java的单继承问题,因为内部类和外部类可以相互访问,包括private成员。
- 外部类访问内部类的实例成员,需要先创建内部类的对象
- 内部类访问外部类的实例成员:
外部类名.this.属性
外部类对象.new 内部类()
/new 外部类.内部类()
- 内部类的类型: 外部类.内部类
- static内部类不可以直接访问 non-static (方法)、成员 创建静态内部类的方式: 外部类.内部类 变量名 = new 外部类.内部类 ;
- 外部类的修饰符:
public
package-access
abstract
final
,abstract
final
不能同时出现 - 成员内部类属于外部类的⼀部分,可以使用所有修饰符
匿名内部类
匿名内部类是一种特殊的局部内部类;所谓匿名,指的是程序员不需要为这个类声明名字。
下面就是匿名内部类的格式:
new 抽象类/接口([参数列表]){
@Override
重写父类/接口的方法;
}
匿名内部类本质上是一个没有名字的子类对象、或者接口的实现类对象。
比如,先定义一个Animal抽象类,里面定义一个cry()方法,表示所有的动物有叫的行为,但是因为动物还不具体,cry()这个行为并不能具体化,所以写成抽象方法。
public abstract class Animal{
public abstract void cry();
}
接下来,我想要在不定义子类的情况下创建Animal的子类对象,就可以使用匿名内部类
public class Test{
public static void main(String[] args){
// 这里后面new 的部分,其实就是一个Animal的子类对象
// 这里隐含的有多态的特性: Animal a = Animal的子类对象;
Animal a = new Animal(){
@Override
public void cry(){
System.out.println("猫喵喵喵的叫~~~");
}
};
a.eat(); // 直接执行上面重写的cry()方法
}
}
或者一个接口
public interface Non_name {
void sound();
}
public class Test01 {
public static void main(String[] args) {
Non_name no=new Non_name(){
@Override
public void sound() {
System.out.println("小鸟叽叽喳喳的叫!");
}
};
no.sound();
}
}
需要注意的是,匿名内部类在编写代码时没有名字,编译后系统会为自动为匿名内部类生产字节码,字节码的名称会以 外部类$1.class 的方法命名
匿名内部类的作用:简化了创建子类对象、实现类对象的书写格式。
**只有在调用方法时,当方法的形参是一个接口或者抽象类,为了简化代码书写,而直接传递匿名内部类对象给方法。**这样就可以少写一个类。
public abstract class Swimming{
public abstract void swim();
}
public class Test{
public static void main(String[] args){
Swimming s1 = new Swimming(){
@Override
public void swim(){
System.out.println("狗刨飞快");
}
};
go(s1);
Swimming s = new Swimming() {
@Override
public void swim() {
System.out.println("淹死的都是会游泳的。");
}
};
go(s);
}
// 形参是Swimming类,实参可以接收任意Swimming类的子类对象
public static void go(Swimming s){
System.out.println("开始~~~~~~~~");
s.swim();
System.out.println("结束~~~~~~~~");
}
}
- 匿名类是没有明确的名称的类
- 匿名类不能有访问修饰符,在方法的内部,对外隐藏。不能是
static
final
类 - 匿名类没有类名,没有构造方法,匿名类不能定义接⼝,不能定义静态块,静态⽅法,静态变量
- 匿名类可以访问类中的成员,不能访问⽅法中的变量,除⾮是 final 的
- 匿名类⼀般是实现接⼝,继承抽象类,相当于实现、继承了这个接⼝、类