概述
java修饰符有以下两种
- 访问修饰符
private:私有访问修饰符,仅类内可见
protected:受保护,仅同包内可见
defult:默认,仅同包内可见
public:公有,所有包可见,只需导入包 - 非访问修饰符
static:用于声明静态方法,变量
final:用于声明不可修改的类,方法,常量
abstract:创建抽象类和抽象方法
synchronized:声明的方法同一时间只能被一个线程访问
transient:修饰的实例变量不会被序列化
volatile:修饰的成员变量强制从共享内存中读取
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修饰变量的时候确实是,不可变的是变量的引用而非引用指向对象的内容
其他要点分析
- 类默认和接口默认并不相同,接口变量默认为public static final,接口方法默认为public
- 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();
}
}
想我所见,思我说闻
写我所想,写我所思
不求处处皆对
只求问心无愧
网友评论