内部类

本文详细介绍了Java中的内部类,包括非静态内部类和静态内部类的定义、特点和访问规则。非静态内部类可以访问外部类的私有成员,而静态内部类不能。此外,还讨论了局部内部类、匿名内部类的使用,以及Java8中匿名内部类的改进。文章强调了内部类在封装和一次性使用类方面的优势,并提供了多个示例来说明其用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:内部类的定义

1)定义在其他类中的类被称为内部类,也叫嵌套类,包含内部类的类也被称为外部类。

二:内部类的优点

1)内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一包下的其它类访问该类;

2)内部类成员可以直接访问外部类的私有数据,因为内部类被当成外部类的成员,同一类的成员之间可以互相访问的,但外部类不能访问内部类的实现细节,例如内部类的成员变量;

3)匿名内部类适合用于创建那些仅需要一次使用的类。

4)内部类比外部类可以使用三个修饰符:private、protected、static——外部类不可以使用这三个修饰符。

5)非静态内部类不能拥有静态成员。

三:非静态内部类

内部类定义只要把一个类放在另一个类内部定义即可。颞部类定义格式

 public class OuterClass{
        //在此处定义内部类
    }

注意:成员内部类是一种与成员变量、方法、构造器和初始化块相似的类成员;局部内部类和匿名内部类则不是类成员;

1)成员内部类分为两种:静态内部类和非静态内部类,使用static修饰的成员内部类是静态内部类,没有使用static修饰的类是非静态内部类。

2)因为内部类作为其外部类的成员,所以可以使用任意访问控制符如private、protected、和public等修饰。

3.2:定义一个非静态内部类,并在内部类中访问外部类的private的实例变量

package Demo;

/**定义一个内部类
 * @author Administrator
 * @ CowLeg 定义一个非静态的内部类
 * @test 编写一个测试方法
 */
public class InsideClass {
    public InsideClass(double weight) {
        this.weight = weight;
    }

    public InsideClass() {
    }

    /**
     * 定义一个私有的成员变量
     */
    private double weight;
    private class CowLeg{
        //非静态成员内部两个成员变量
        private double length;
        private String color;

        public double getLength() {
            return length;
        }

        public void setLength(double length) {
            this.length = length;
        }

        public String getColor() {
            return color;
        }

        public void setColor(String color) {
            this.color = color;
        }

        public CowLeg(double length, String color) {
            this.length = length;
            this.color = color;
        }

        public CowLeg() {
        }
        //非静态内部类的实例方法
        public void info(){
            System.out.println("当前牛腿的颜色是:"+color+",高:"+length);
            //直接访问外部类的private修饰的成员变量
            System.out.println("本牛腿的所在的牛的体重:"+weight);
        }

    }
    public void test(){
        CowLeg cowLeg =new CowLeg(1.12,"黄的");
        cowLeg.info();
    }

    public static void main(String[] args) {
        InsideClass insideClass = new InsideClass(389.1);
        insideClass.test();
    }

}

结果

在外部类使用内部类方法时,与平时使用普同类没有太大的区别。

3.3)静态内部类的方法访问某个成员变量的顺序为

系统会优先在该内部类内部方法体里面查找该方法使用名字相同的成员变量 ,如果查询不到,会在内部类里面查询,在找不到该变量 ,会在外部类查询,在找不到,会报错,找不到该成员变量。(下面用图描述了一下)

 

2)如果外部类成员变量、内部类成员变量与内部类方法变量同名,则可以使用this。外部类类名.this 作为限定来区分。代码如下:

 

package Demo;

/**
 * @author Administrator
 */
public class SameInsideClass {
    private String sameName = "中国伟大复兴";
    public class InsideClass{
        private String sameName ="中国人民自强不息";
        //创建一个内部类方法
        public void info(){
            System.out.println(this.sameName);
            System.out.println(SameInsideClass.this.sameName);
        }
    }

    /**
     * @test测试类
     */
    public void test(){
        InsideClass insideClass = new InsideClass();
        insideClass.info();
    }

    public static void main(String[] args) {
//        SameInsideClass sameInsideClass = new SameInsideClass();
//        sameInsideClass.test();
        //这两种方法 调用都可以
        new SameInsideClass().test();
    }
}

结果

内部类的良好的封装从侧面也体现出来了

 

3.4)外部类怎么访问非静态内部类的成员变量

非静态内部类可以访问外部类的private成员,但反过来就不成立,非静态内部的成员只在非静态内部类范围内是可知的,并不能被外部类所使用,如果外部类需要访问非静态内部类的成员变量,则必须显示创建非静态内部类对象类调用访问其实例成员。

package Demo;

/**
 * @author Administrator
 */
public class VisitInsideClassMember {
    private String name = "张三";

    public class InsideClass {
        //内部类成员变量
        private String name1 = "李四";

        public void visitOutMember() {
            //内部类可以直接访问外部类的私有成员变量
            System.out.println(name);
        }
    }

    public void outClassMethod() {
        //外部类访问内部类的成员变量
        //显示报错  System.out.println(name1);
        //如果访问内部类成员变量,必须显式创建内部类对象
        InsideClass insideClass = new InsideClass();
        System.out.println(insideClass.name1);
      //输出内部类直接调用外部类的结果
        insideClass.visitOutMember();

    }

    public static void main(String[] args) {
        VisitInsideClassMember v = new VisitInsideClassMember();
        v.outClassMethod();


    }
}

 

结果

注意事项解释图

3.5)非静态内部类其他总结

1)外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量。创建实例。总之,不允许在外部类的静态成员中直接使用非静态非静态内部类。

2)非静态内部类里不能有静态方法。静态成员变量,静态初始化块、

四:静态内部类

4.1)静态内部类定义

如果使用static来修饰的一个内部类,则这个内部类就属于外部内部类本身,而不属于外部类的某个对象。因此使用static修饰的内部类被称为类内部类,有的地方也称为静态内部类。

4.2)静态内部类可以包含静态成员,也可以包含非静态成员,根据静态成员不能访问非静态成员的规则,静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。即使是静态内部类的实例方法也不能访问外部类的实例成员,之能访问外部类的静态成员

package Demo;

/**
 * @author Administrator
 */
public class StaticInnerClassTest {
    private  int prop = 5;
    private static int prop1 = 8;
    static class StaticInnerClass{
        //静态内部类可以包含静态成员变量
        private static int age;
        public void accessOuterProp(){
            //下面代码出现错误
            //静态内部类无法访问外部类的实例变量
           // System.out.println(prop);
            //下面代码正常
            System.out.println(prop1);
        }
    }
}

4.3)外部类依然不能直接访问静态内部类成员,但可以使用静态内部类的类名作为调用者来访问内部列的类成员。(下面代码演示)

package Demo;

/**
 * @author Administrator
 */
public class StaticInsideClass {
    static class StaticClass{
        private static int age;
        private int ddd;
    }
    public void test(){
       //System.out.println(age);
        //通过类名访问静态内部类的变量
        System.out.println(StaticClass.age);
        //通过实例访问静态内部类的实例成员
        System.out.println(new StaticClass().ddd);
    }
}

注意:java还允许在接口定义内部类,接口定义内部类默认使用public static 修饰,也就是说接口内部类只能是静态内部类。

五:使用内部类(使用场景)

1)在外部类内部使用内部类

2)在外部类以外使用非静态内部类

5.1在外部类以外地方创建非静态内部类对象,并把它赋值给非静态内部类类型的变量。(非静态内部类)

package Demo;

/** 在外部以外的地方创建非静态内部类的对象
 * @author Administrator
 */
class  Out{
  //定义一个内部类不使用访问控制符
  //即只有同一个包中的其他类可访问该内部类
    class  In{
        public In(String msg){
            System.out.println(msg);
        }
  }
}

public class CreateInnerInstance {
    public static void main(String[] args) {
        Out.In in = new Out().new In("测试信息");
        
    }
}

5.2:在外部类以外的地方创建静态内部类对象

 

package Demo;

/**
 * @author Administrator
 */
class OutStatic{
    //定义一个静态内部类,不使用访问控制符,同一个包中的其他类可访问该内部类
    static class StaticIn{
        public StaticIn(){
            System.out.println("静态内部类的构造器");
        }
    }
}
public class GreatStaticInnerInstance {
    public static void main(String[] args) {
        OutStatic.StaticIn in = new OutStatic.StaticIn();
    }
}

从上面代码可以看出,不管是静态内部类还是非静态内部类,他们声明的语法完全一样。

六:局部内部类

1)如果把一个内部类放在一个方法里面定义,则这个内部类称为局部内部类;

2)局部内部类仅在该方法里面有效;

3)由于局部内部类不能在外部类的方法以外的地方使用,因此局部内部类也不能使用访问控制符和Static修饰符修饰。

定义局部内部类

package Demo;

/**
 * @author Administrator
 */
public class LocalInnerClass {
    public static void main(String[] args) {
        //定义局部内部类
        class InnerBase {
            int a;
        }
        //定义局部内部类
        class InnerSub extends InnerBase {
            int b;
        }
        //创建局部内部类对象
        InnerSub is = new InnerSub();
        is.a = 5;
        is.b = 8;
        System.out.println(is.a+","+is.b);


    }
}

 

七:java8该进的匿名内部类

1)匿名内部类适合创建那种只需要一次使用的类

2)匿名内部类的格式

new 实现接口()| 父类构造器(实参列表)

{

//匿名内部类的类体部分

}

3)匿名内部类规则

1.匿名内部类不能是抽象类,因为系统在创建匿名内部类的时候,会立即创建匿名内部类的对象,因此不允许将匿名内部类定义成抽象类;

2.匿名内部类不能定义构造器。因为匿名内部类没有类名,所以无法定义构造器,但是匿名内部类可以定义初始化块,可以通过实例化块来完成构造器需要完成的事情。

4)匿名内部类的使用场景

1.常用的创建内部匿名类的方式是需要创建某个接口类型的对象;(下面代码)

package Demo;

/**
 * @author Administrator
 */
interface Product{
    public double getPrice();
    public  String getName();
}
public class AnonymousTest {
    public void test(Product p){
        System.out.println("购买了"+p.getName() +"消费了"+ p.getPrice());
    }

    public static void main(String[] args) {
        AnonymousTest anonymousTest = new AnonymousTest();
        anonymousTest.test(new Product() {
            @Override
            public double getPrice() {
                return 563.63;
            }

            @Override
            public String getName() {
                return "冰箱";
            }
        });
    }
}

 

 

5)在java8之前,java要求被局部内部类、匿名内部类访问的局部变量必须使用final修饰,之后java8 取消了,java8更加智能:如果局部变量被匿名颞部类访问,那么局部变量相当于自动使用了final修饰 。如下(了解就行)

 

package Demo;

/**
 * @author Administrator
 */
interface A{
    void test();
}
public class ATest {
    public static void main(String[] args) {
        int age = 8;
        A a = new A() {
            @Override
            public void test() {
                //在java8之前 下面语句报错 age 必须加final修饰
                System.out.println(age);
            }
        };
        a.test();
    }
}

 

总结 :学习还是中午 下午 学的太慢了  今天结束  O(∩_∩)O哈哈~!

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值