目录
一.Static
1.1 静态属性
1.2 静态方法
1.3 动态代码块与类加载
二.final
java中的五大存储区域:
栈、堆、方法区、寄存器区、本地方法区
寄存器区:主要是线程的存储区域
本地防区:第三方语言的存储区域,例如:c/c++
重点分析三大区域:堆,栈,方法区
栈:存局部变量 (引用对象,基本变量)
堆:new对象,成员属性
方法区:class文件,静态区(static修饰),常量池(字符串常量)-往往方法区的东西只有一份
①成员属性
class MyClass{ int a; //成员属性 } public class Test1 { public static void main(String[] args) { MyClass obj1 = new MyClass(); MyClass obj2 = new MyClass(); obj1.a = 3; obj2.a = 5; System.out.println(obj1.a+"---"+obj2.a); } }
②静态属性
//实例属性 VS 静态属性 //实例属性: 在堆区,属于对象,通过对象调用;每个对象独有的一份 //静态属性: 在方法区,属于类,推荐使用类名调用;所有对象共享同一份 class MyC{ static int a; } public class Test2 { public static void main(String[] args) { MyC obj1 = new MyC(); MyC obj2 = new MyC(); //The static field MyC.a should be accessed in a static way obj1.a = 3; //MyC.a = 3; 静态属性属于类,推荐通过类名调静态属性 obj2.a = 5; System.out.println(obj1.a+"---"+obj2.a); } }
//问题:在静态方法中,能否使用成员属性;--不能 //在成员方法中能否使用静态属性?--能 为什么? //思考: 函数入口为何要这么设计? public static void main() //public:公开权限,使得外部jvm有权限调用 //static:优先加载,无需new对象,提高性能 //void: 无需反馈结果到jvm class MyClass{ static int a; //静态属性 int b; //成员属性 //静态方法中不能使用this与super关键字--加载时机问题 //静态方法可以继承,但不能重写 public static void test() { //静态方法 System.out.println("测试的方法..."); //加载时机问题,静态区在类加载时就进行加载了,这时还不知道对象属性; 静态区优先对象加载 //System.out.println(b); } public void print() { System.out.println(a); } } class Son extends MyClass{ /*@Override public static void test() { //静态方法,不能重写 }*/ } public class Test1 { public static void main(String[] args) { //之前方法调用,因为是调当前类的方法,所有省略了类名的调用 System.out.println(add(1,2)); //调当前类的方法 等价Test1.add(1,2); //The static method add(int, int) from the type Test1 should be accessed in a static way System.out.println(new Test1().add(3, 5)); //可以通过对象调静态方法,但是不推荐 //调用系统提供的静态方法 int[] a = {1,2,3}; System.out.println(Arrays.toString(a)); //调其他类的方法: 类名.方法 MyClass.test(); //调用自定义类的静态方法 //new Son().test(); //静态方法具有继承性 } //静态方法:属于类,推荐使用类名调用 public static int add(int a, int b) { return a+b; } }
①动态代码块
//动态代码块: 就是类中的一块区域,只要在类中加入{},就是一个代码块; //通过实例化对象可以触发到动态代码块 //执行流程: //成员属性>动态代码块>构造方法 //作用: 给属性赋予初始值 //类加载过程: //jvm根据classpath查找class文件,并将class文件中的所有信息(包名,类名,对象,属性,方法等)加载到内存中 //需要在入口main中触发执行类加载 class MyClass{ String a = "成员属性"; static String b = "静态属性"; { System.out.println(a); System.out.println("动态代码块"); } public MyClass() { System.out.println("构造方法"); } public static void show() { System.out.println("调用静态方法"); } } class Son extends MyClass{ } public class Test1 { public static void main(String[] args) throws ClassNotFoundException { //new MyClass(); //实例化对象触发 //new Son(); //实例化子类对象 //System.out.println(MyClass.b); //静态属性触发类加载 //MyClass.show(); //使用静态方法触发类加载 Class.forName("com.qf.c_statickuai.MyClass"); //加入全限定名,触发类加载-反射后面学 } }
②静态代码块
//静态代码块的执行: //先执行静态属性>静态代码块(通过反射触发) class MyC{ static String a = "静态属性"; //静态代码块 static { System.out.println(a); System.out.println("静态代码块"); } } public class Test2 { public static void main(String[] args) throws ClassNotFoundException { Class.forName("com.qf.c_statickuai.MyC"); } }
③动态代码块与静态代码块
//对象的执行过程(动态代码块+静态代码块): //规则: 先静态,后动态 静态属性->静态代码块->成员属性->动态代码块->构造方法 //再new一个对象: 再执行一次,成员属性->动态代码块->构造方法 //结论:static与对象无关,静态代码块只加载一次,优先于非静态的执行 class Super{ static String a = "父类静态属性"; String b = "父类成员属性"; static { System.out.println(a); System.out.println("父类静态代码块"); } { System.out.println(b); System.out.println("父类动态代码块"); } public Super() { System.out.println("构造方法"); } } public class Test1 { public static void main(String[] args) { new Super(); //实例化当前类的构造方法 先静态,后动态 System.out.println("==============="); new Super(); //再new一个对象 } }
④子类的实例化过程
//案例:子类继承Super类,观察子类实例化过程 //规则: 先父类,再子类,先静态,后动态 //执行流程:父类静态属性>父类静态代码块>子类静态属性>子类静态代码块>父类成员属性>父类动态代码块 // 父类构造方法>子类成员属性>子类动态代码块>子类构造方法 class Son extends Super{ static String a = "子类静态属性"; String b = "子类成员属性"; { System.out.println(b); System.out.println("子类动态代码块"); } static { System.out.println(a); System.out.println("子类静态代码块"); } public Son() { System.out.println("子类构造方法"); } } public class Test2 { public static void main(String[] args) { new Son(); } }
final:表示最终的,可以修饰类,方法,属性
修饰类:最终类(太监类),被final修饰的类不能有子类
修饰方法: 该方法不能被重写
修饰属性: 变量变为了常量,往往在静态属性中与static配合使用(状态值)-静态常量
//final修饰类,该类不能有子类 /*final*/ class Super{ //静态常量必须初始化时要赋值 //静态常量赋值时机:1.初始时赋值 2.静态代码块 public final static int COUNT=1; //状态值往往是不能被改变的,+final修饰则变为了常量 /*static { COUNT = 2; }*/ //成员常量必须初始化时要赋值 //成员常量赋值时机: 1. 初始时赋值 2.动态代码块 3.构造方法 public final int d=1; /*{ d = 3; }*/ /*public Super() { d = 5; }*/ //final修饰方法,该方法不能被重写 public /*final*/ void test(){ } } //The type Son cannot subclass the final class Super class Son extends Super{ int b; @Override //Cannot override the final method from Super public void test(){ } } public class Test1 { public static void main(String[] args) { //Super.COUNT = 5; //The final field Super.COUNT cannot be assigned //基本类型的局部变量中的final修饰: 该变量值不能改变 final int a = 3; //a = 5; 不能改变 //引用类型的局部变量中加final修饰: 该变量地址不能改变,与属性值无关 final Son son = new Son(); //son.b = 6; //son = new Son(); //地址不能改变 //数组也是引用类型,修饰数组后,地址不能变,里面的元素值可以变 final int[] c = {1,2,3}; //c = new int[]{4,5}; //地址不能改变 c[0] = 6; } }
(=1=,距离10.24程序猿节还有两天,今天小白玩转盘活动,成功收获一个纪念杯!在这也提前祝大伙程序员节快乐!)