内部类与静态内部类

前言

  如果你是一个急性子,没什么耐性的人,可以只看下句,自己去品味理解:

  内部类:就是我是你的一部分,我了解你,我知道你的全部,没有你就没有我。(所以内部类对象是以外部类对象存在为前提的)

  静态内部类:就是我跟你没关系,自己可以完全独立存在,但是我就借你的壳用一下,来隐藏自己。

  如果还不知道静态和普通成员的区别,就先学static吧。

  静态成员:属于这个类,数据存放在class文件中,程序运行之前就已经存进去数据了。

  普通成员:属于这个类的对象,程序运行后生成堆栈中。

  先来看一下官方说法,根据Oracle官方的说法:

  Terminology: Nested classes are divided into two categories: static and non-static. Nested classes that are declared static are called static nested classes. Non-static nested classes are called inner classes.

  一个称为静态嵌套类(静态内部类),一个称为内部类。那么两者到底有什么区别呢?很多JDK源码用到了静态内部类。HashMap、ThreadLocal、AQS的sync等。那么接下来学习一下内部类吧!

内部类

  内部类是定义在另外一个类中的类,主要原因有:

  • 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据
  • 内部类可以对同一个包的其他类隐藏

  静态内部类和非静态内部类最大的区别是:非静态内部类编译后隐式保存着外部类的引用(就算外部类对象没用了也GC不掉),但是静态内部类没有。

1.1 非静态内部类

1.1.1 定义

  内部类定义语法格式如下:

class OuterClass {
    ...
    class NestedClass {
        ...
    }
}

  我们直接先看来一个例子吧,在Human类里定义了一个HumanLeg非静态内部类,并且在HumanLeg类的实例方法中直接访问外部类的private访问权限的实例变量和类变量。

/**
 * 人类 - 外部类
 *
 * @author GrimMjx
 */
public class Human {

    private static final int eyes = 2;

    private static void count() {
        System.out.println("I can count number");
    }

    private int teeth = 10;

    private void say() {
        System.out.println("Hello world");
    }

    /**
     * 人腿 - 非静态内部类
     */
    public class HumanLeg {
        private Double length;

        public HumanLeg(Double length) {
            this.length = length;
        }

        public void test() {
            say();
            count();
            System.out.println("I have " + eyes + " eyes");
            System.out.println("I have " + teeth + " teeth");
            System.out.println("My leg has " + length.toString() + "cm long");
        }
    }

    public static void main(String[] args) {
        Human human = new Human();
        HumanLeg humanLeg = human.new HumanLeg(100D);
        humanLeg.test();
    }
}

  运行结果:

Hello world
I can count number
I have 2 eyes
I have 10 teeth
My leg has 100.0cm long

  由此看出,非静态内部类可以直接访问外部类的实例变量、类变量、实例方法、类方法。这是因为在非静态内部类对象里,保存了一个它所寄生的外部类对象的引用(非静态内部类实例必须寄生在外部类实例里)。也就是说,非静态内部类对象总有一个隐式引用,指向了创建它的外部类对象。我们来画一张示意图来理解一下。

  另外,还有一些要注意的点

  • 非静态内部类的成员只是在非静态内部类范围是可知的,并不能被外部类直接使用,如果要访问非静态内部类的成员必须显示创建非静态内部类对象来调用访问!
  • 根据静态成员不能访问非静态成员的规则,外部类的静态方法不能访问非静态内部类。
  • 非静态内部类不允许定义静态成员。如下面例子所示:
/**
 * @author GrimMjx
 */
public class Test {

    class Inner{
        static {

        }

    }

    // 静态成员无法访问非静态成员
    public static void main(String[] args) {
        new Inner();
    }
}

1.1.2 内部类的特殊语法规则

  如果非静态内部类方法访问某个变量,其顺序为

  1. 该方法是否有该名字的成员变量 - 直接用该变量名
  2. 内部类中是否有该名字的成员变量 - 使用this.变量名
  3. 外部类中是否有该名字的成员变量 - 使用外部类的类名.this.变量名

  接下来看一个例子:

/**
 * @author GrimMjx
 */
public class Outer {

    private int i = 1;

    public class Inner {
        private int i = 2;

        public void print() {
            int i = 3;
            System.out.println(i);
            System.out.println(this.i);
            System.out.println(Outer.this.i);
        }
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        Inner inner = outer.new Inner();
        inner.print();
    }
}

  运行结果:

3
2
1

1.2 静态内部类

  如果用static来修饰一个内部类,那么就是静态内部类。这个内部类属于外部类本身,但是不属于外部类的任何对象。因此使用static修饰的内部类称为静态内部类。静态内部类有如下规则:

  • 静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。
  • 外部类可以使用静态内部类的类名作为调用者来访问静态内部类的类成员,也可以使用静态内部类对象访问其实例成员。
/**
 * 静态内部类测试外部类。
 *
 * @author GrimMjx
 */
public class StaticInnerTest {
    private int x = 1;
    private static int y = 2;

    public void test(){
        System.out.println(new InnerClass().a);
        System.out.println(InnerClass.b);
    }

    static class InnerClass {
        private int a = 3;
        private static int b = 4;

        public void test(){
            //无法访问
//            System.out.println(x);
            System.out.println(y);
        }
    }

    public static void main(String[] args) {
        StaticInnerTest staticInnerTest = new StaticInnerTest();
        staticInnerTest.test();

        InnerClass innerClass = new InnerClass();
        innerClass.test();
    }
}

原文地址:https://www.cnblogs.com/GrimMjx/p/10105626.html

时间: 2024-11-12 16:53:53

内部类与静态内部类的相关文章

java内部类和静态内部类

看代码理解内部类,局部内部类和静态内部类 内部类代码: public class InnerTest { private static String name; private int age; public InnerTest(String name, int age){ this.name = name; this.age = age; } public void getInstance() { System.out.println("name:" + name.toString(

内部类及静态内部类的实例化

内部类的实例化 如果内部类未声明为static,在实例化时首先需要new一个外部类的对象.并通过p.new Inner()的方式new 内部类,表明这个内部类指向该外部类.内部类的class类型为:Parent.Inner,而不是p.Inner,这个需要和new的方式区分开. public class Test {  public static void main(String[] args) {   Parent p = new Parent();   Parent.Inner i = p.n

Java中的嵌套类、内部类、静态内部类

在Java中我们在一个类的内部再定义一个类,如下所示: class OuterClass { ... class NestedClass { ... } } 那么在上面的例子中我们称OuterClass为外围类(enclosing class),里面的那个类称之为嵌套类(Nested Class). 嵌套类可以分为两种,静态的和非静态的,即静态嵌套类和非静态嵌套类.非静态嵌套类又叫做内部类(Inner Class).我们通常所说的静态内部类其实是不严格的,严格的说应该叫做静态嵌套类(Static

java 内部类和静态内部类的区别

下面说一说内部类(Inner Class)和静态内部类(Static Nested Class)的区别:定义在一个类内部的类叫内部类,包含内部类的类称为外部类.内部类可以声明public.protected.private等访问限制,可以声明 为abstract的供其他内部类或外部类继承与扩展,或者声明为static.final的,也可以实现特定的接口.外部类按常规的类访问方式使用内部 类,唯一的差别是外部类可以访问内部类的所有方法与属性,包括私有方法与属性. (1)创建实例 OutClass.

内部类之静态内部类

一.位置 被定义在一个类下,且被static修饰 二.结构 静态内部类下可以定义静态和非静态的属性和方法 三.静态内部类访问外部类 1.不能访问外部类非静态的属性和方法 2.调用属性[方法]方式: 2.1直接写属性名[调用方法名]-------本质还是第二种 2.1外部类.属性名[方法名] 源码: class Outter { private static int b =3; public static void test(){ System.out.println("外部类静态方法"

Java内部类(4):静态内部类&接口内部类

使用static修饰的内部类我们称之为静态内部类,不过我们更喜欢称之为嵌套内部类.静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有.没有这个引用就意味着: 1. 它的创建是不需要依赖于外围类的. 2. 它不能使用任何外围类的非static成员变量和方法. 1 interface Contents { 2 int value(); 3 } 4 5 interface Destination {

静态非静态内部类匿名内部类局部内部类

内部类有静态内部类,静态内部类,匿名内部类,局部内部类 (1)非静态内部类 直接在类的内部定义的类就是非静态内部类,如下 public class Test { public static void main(String[] args) { Outer.Inner c1=new Outer().new Inner(); c1.Print(); } } class Outer{ private int temp=10; class Inner{ private int temp=100; pub

java的四种内部类(转)

一般来说,有4中内部类:常规内部类.静态内部类.局部内部类.匿名内部类. 一.常规内部类:常规内部类没有用static修饰且定义在在外部类类体中.  1.常规内部类中的方法可以直接使用外部类的实例变量和实例方法.  2.在常规内部类中可以直接用内部类创建对象  3.代码如下: public class MyOuter { private int x = 100; // 创建内部类 class MyInner {  private String y = "Hello!"; public

java 内部类与外部类的区别

最近在看Java相关知识的时候发现Java中同时存在内部类以及非公有类概念,而且这两个类都可以不需要单独的文件编写,可以与其他类共用一个文件.现根据个人总结将两者的异同点总结如下,如有什么不当地方,欢迎大家指正. 1.非公有类和内部类对应的文件名与这两种类的类名无关: 2.一个源文件中可以包含多个非公有类或者内部类: 3.非公有类不能使用public关键字(一般前面不加关键字),内部类可以使用public.private.protected关键字: 4.非公有类中可以添加0到多个内部类: 5.非