java修饰符

2019-11-04  本文已影响0人  幻想的绝望

概述

java修饰符有以下两种

static要点分析

static修饰的变量为类变量,修饰的方法为类方法,可通过类名直接调用。(修饰类,这个类就是静态内部类)
从jvm虚机机类加载角度看,静态资源是类初始化的时候加载的,而非静态资源是类new的创建对象的时候加载的。静态资源的加载早于非静态资源。所以静态方法不可以引用非静态资源,非静态方法可以引用静态资源。

public class A {
    private static int a = s2();

    static {
        System.out.println("this is s1");
    }

    static int s2() {
        System.out.println("this is s2");
        return 1;
    }

    public A() {
        System.out.println("this is A()");
    }

    public static void main(String[] args) {
        new A();
    }
}
输出结果
this is s2
this is s1
this is A()

说明静态资源的加载顺序是按照资源定义的顺序加载的,且先于非静态资源

public class B {
    static {
        i = 3;
        System.out.println(i);
    }
    private static int i;
}

第四行输出i编译器直接提示报错,说明静态代码块对于定义在它之后的静态变量,可以赋值,但是不能访问

public class C {
    static {
        System.out.println("c.static");
    }

    public C(){
        System.out.println("c.public");
    }
}

public class D extends C {
    static {
        System.out.println("d.static");
    }

    public D(){
        System.out.println("d.public");
    }

    public static void main(String[] args) {
        new D();
        new D();
    }
}

输出结果
c.static
d.static
c.public
d.public
c.public
d.public

说明静态代码先执行父类,再执行之类,且只执行一遍

public class Hello {

    public static void main(String[] args) {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        printClassesOfClassLoader(loader);
        System.out.println("hello  " + A.class);
        printClassesOfClassLoader(loader);
    }

    public static void printClassesOfClassLoader(ClassLoader loader){
        try {
            Field classesF = ClassLoader.class.getDeclaredField("classes");
            classesF.setAccessible(true);
            Vector<Class<?>> classes = (Vector<Class<?>>) classesF.get(loader);
            for(Class c : classes) {
                System.out.println(c);
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

程序输出
class com.intellij.rt.execution.application.AppMainV2$Agent
class com.intellij.rt.execution.application.AppMainV2
class com.intellij.rt.execution.application.AppMainV2$1
class statics.Hello
hello  class statics.A
class com.intellij.rt.execution.application.AppMainV2$Agent
class com.intellij.rt.execution.application.AppMainV2
class com.intellij.rt.execution.application.AppMainV2$1
class statics.Hello
class statics.A

接着上面的A类,以上代码运行后,程序输出中并没有出现A中的静态代码块输出的内容,但是类加载器里面的确有了A类。为什么A.class这种方式不会触发A内的静态代码块的执行呢?
这就要提到java类加载的五个过程加载,验证,准备,解析,初始化。在Java方法区中创建A.Class的类信息发生在加载阶段,运行静态块内容则发生在初始化阶段

final要点分析

final修饰类,类不可被继承
final修饰方法,方法不可被重写
final修饰变量,变量不可改变

    public static void main(String[] args) {
        final String[] s = {"aaa", "bbb"};
        s[1] = "ccc";
        //s = new String[2];//无法使用,程序报错
    }

第三行没问题,第四行程序提示bug,说明变量的不可改变,指的是引用不可改变,但是引用指向的内容可以改变

final String s = "a"

重点说说这个,这个a存在于常量池中,s存储的是指向a的地址,如果把s赋值为"b",本质上是把s存储的地址改成b的,当然修改时不会成功的。所以本质上来说final修饰变量的时候确实是,不可变的是变量的引用而非引用指向对象的内容

其他要点分析

  1. 类默认和接口默认并不相同,接口变量默认为public static final,接口方法默认为public
  2. protected修饰符,经测试,子类父类在不同包,子类不可见父类的protected方法
public class Student extends People {

    protected void say4() {
        System.out.println("2");
    }

    public static void main(String[] args) {
        People p = new Student();
        //p.say4();//无法使用,会报错

        Student s = new Student();
        s.say4();
    }
}
想我所见,思我说闻
写我所想,写我所思
不求处处皆对 
只求问心无愧
上一篇 下一篇

猜你喜欢

热点阅读