权限修饰符

分类

  • private私有的;
  • default默认的;
  • protected受保护的;
  • public公共的;
修饰符 本类 同一包 不同包 全局范围
private Y
default Y Y
protected Y Y Y
public Y Y Y Y
类修饰符 成员变量 成员方法 构造方法
private F T T T
default T T T T
protected T T T F
public T T T T
abstract(抽象修饰符) F T F T
final(最终修饰符) T T F T
static(静态修饰符) T T F F

内部类

什么是内部类?

大部分时候,类被定义成一个独立的程序单元,在某些情况下也会把一个类放在另一个类的内部定义,这个定义在其他内部的类就被称为内部类,包含内部类的类也被称为外部类

内部类的分类

  • 非静态内部类
  • 静态内部类
  • 成员内部类
  • 局部内部类

内部类的作用

  • 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类。
  • 内部内成员可以直接访问外部类的私有数据,因为内部类被当做外部内的成员,同一个类的成员之间可以相互访问。但外部内不能访问内部类的实现细节。
  • 匿名内部类适合用于创建那些仅需要创建一次使用的类。

内部内规则

  • 内部类比外部类可以多使用三个修饰符:private、protected、static外部类不可以使用这三个修饰符。
  • 非静态内部类不能拥有静态成员。

非静态内部类

定义语法:

public class OuterClass
{
class InterClass{}
}

大部分时候,内部类都被作为成员内部类定义,而不是作为局部内部类。成员内部类是一种与成员变量、方法、构造器和初始化块相似的类成员;局部内部类和匿名类则不是类成员。

案例:

package org.westos.practice;

public class Cow {
    private double weight;

    //外部类的两个重载构造器
    public Cow(){}
    public Cow(double weight){
        this.weight=weight;
    }

    //定义一个非静态内部类
    private class CowLeg{
        //非静态内部类的两个实例变量
        private double length;
        private String color;

        //非静态内部类里的两个重载构造器
        public CowLeg(){}

        public CowLeg(double length, String color) {
            this.length = length;
            this.color = 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 void info(){
            System.out.println("当前牛腿的颜色"+color+"高"+length);
            //直接访问外部内的成员变量
            System.out.println("当前牛腿的重量"+weight);
        }
    }
    public void test(){
        CowLeg cowLeg = new CowLeg(1.12,"white");
        cowLeg.info();
    }

    public static void main(String[] args) {
        Cow cow = new Cow(500);
        cow.test();

    }
}

可以看到在文件所在路径生成的两个class文件,一个是Cow.class,另一个是CowLeg.class。
Java内部类、修饰符

内部内访问外部类成员变量的机制

在非静态内部类对象里保存了一个它所寄生的外部类对象的引用。

在非静态内部类的方法内访问访问某个变量时,系统由现在该方法内查找是否存在该变量,如果不存在就在内部类中查找成员变量;如果找不到,就在内部类所在的外部类中查找,在如果找不到就出现编译错误。

案例:
一次注释掉局部变量,内部类变量,外部类变量,一次运行可以看到查找顺序。

package org.westos.practice;

public class NumSearch {
//    int num=10; //外部内成员变量
    class InNumSearch{
//        int num=20; //内部类成员变量
        public void inNumShow(){
            int num=30; //方法内局部变量
            System.out.println(num);
        }
    }

    public void test(){
        InNumSearch inNumSearch = new InNumSearch();
        inNumSearch.inNumShow();
    }

    public static void main(String[] args) {
        NumSearch numSearch = new NumSearch();
        numSearch.test();
    }
}

如果想一次输出三个位置的num,可以用this和类名

			System.out.println(num);
            System.out.println(this.num);
            System.out.println(NumSearch.this.num);

如果外部内想访问内部类的成员,只能显式的实例化内部类的对象,然后通过对象调用;

public void test(){
//        System.out.println(num2);
        //Error:(13, 28) java: 找不到符号
        //  符号:   变量 num2
        //  位置: 类 org.westos.practice.NumSearch

//        创建内部类对象访问
        System.out.println(new InNumSearch().num2);
    }

非静态内部类对象和外部类对象的关系

非静态内部类对象必须寄生在外部类对象里面,而外部类对象则不必一定有非静态内部类对象寄生其中。接单的说,如果存在一个非静态内部类的对象则一定存在被寄生的外部类对象,而如果存在一个外部类对象则它不一定被内部类对象寄生。这就是为什么外部类不能直接访问非静态内部类成员的原因,因为不确定是否有内部对象。而内部类可以访问外部类成员,因为外部类对象一定存在。

不允许在外部类的静态成员中直接使用非静态成员内部类,这和静态成员不能访问非静态成员原因是一样的;
不允许在非静态内部成员里定义静态成员

为什么外部类就可以定义静态成员,而非静态内部类就不可以?

因为对于外部类不存在静态还是非静态这个问题。在编译时外部内中的静态成员和外部类一起被创建。而非静态内部类是在外部类被实例化时才创建,如果非静态内部类中有静态成员,那创建外部类的时候到底是创建非静态内部类的静态成员还是不创建呢?如果创建了,那非静态内部类都没创建,成员还能在类之前创建吗?这是个矛盾的问题。

访问权限
外部类的上一级程序单元是包,所以它只有2个作用域:同一个包内和任何位置。因此只需要2种访问权限:包访问权限和公开访问权限。而内部类的上一级程序单元是外部类,它有4个作用域:同一个类、同一包、父子类和任何位置,因此可以使用4种访问权限。

静态内部类

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

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

package org.westos.practice;

public class OuterClass {
    private static int num1=10;
    private int num2=20;

    public static class InterClass{
        public void show(){
//            System.out.println(num2);
            //Error:(9, 32) java: 无法从静态上下文中引用非静态 变量 num2
            System.out.println(num1);
            //10
        }
    }

    public static void main(String[] args) {
        InterClass interClass = new InterClass();
        interClass.show();

    }
}

因为静态内部类是与外部类相关的,而不是与外部类的对象相关,当静态内部类的对象存在时并不存在一个被它寄生的外部类对象,静态内部类只保存了外部类的类引用,没有持外部类的对象引用,所以在访问外部类实例成员时找不到外部类的对象。

外部类依然不能访问静态内部类的成员,但可以使用静态内部类的类名作为调用者来访问静态内部类的类成员,也可以使用静态内部类对象作为调用者来访问静态内部类的实例成员。

案例;

package org.westos.practice;

public class OuterClass {

    public static class InterClass{
        static int num1=10;
        int num2=20;
    }
    public static void main(String[] args) {
        InterClass interClass = new InterClass();
        System.out.println(OuterClass.num1);
        System.out.println(OuterClass.num2);

    }
}

Java内部类、修饰符

通过类名和对象名访问:

  public static void main(String[] args) {
        InterClass interClass = new InterClass();
        //通过静态内部类类名访问内部类静态成员
        System.out.println(InterClass.num1);
        //通过静态内部类对象名访问内部类非静态成员
        System.out.println(interClass.num2);

    }

接口内部类
Java还允许在接口中定义内部类,接口里定义的内部类默认使用public、static修饰,也就是说,接口内部类只能是静态内部类。这种情况意义不太大。

相关文章: