Java学习笔记(一)
1. Java中的参数传递机制:
- java参数传递是值传递(基本类型是值传递,引用类型相当于地址传递)
- 引用copy一份以后其值所指向的还是同一个对象
- java里的引用其实就是C里的指针,只是对其做了封装,避免开发者进行烦琐的指针操作
2. Java的数据类型:
- 基本数据类型:int,long,bool,float,double,String(属于非引用类型,暂且把它放在这)~
- 引用数据类型:数组 + 对象(引用存放在栈区,真正数据存放在堆区)~
3. Java的垃圾回收机制:
- 当某个对象不被任何引用所指时,Java的垃圾回收机制极可能会回收该对象(不是一定,没有及时性)
- 如果想让某个对象被回收,可通过切断该对象所有引用变量和它之间的关系,即令它们为null(不一定会立即回收,但肯定会回收)
- 系统在回收对象时(去活状态)会调用其finalize()方法
- System.gc()和Runtime.getRuntime.gc()会通知系统尽快回收去活对象资源(但不一定会马上清理,会有一定用处)
- System.runFinalization()和Runtime.getRuntime.runFinalization()方法会强制垃圾回收机制调用去活对象的finalize()方法
4. static修饰的方法中不能使用this引用,故其也不能直接使用非静态方法
5. Java方法的所属性:(static修饰的方法从属于类, 否者从属于对象)
- 方法不能独立定义,只能在类体内定义
- 从逻辑意义上看,方法要么从属于类,要么从属于该类的一个对象
- 永远不能独立执行方法,执行方法必须使用类或者类对象作为调用者
6. Java中允许定义形参长度可变的参数:
eg:
1 public class TestParameter2{ 2 3 /** 4 *定义了形参可变的方法 5 */ 6 public static void test(int a, String... books){ 7 for(String tmp : books){ 8 System.out.println(tmp); 9 } 10 System.out.println(a); 11 } 12 13 public static void main(String[] args){ 14 //掉用testfangfa 15 test(56, "谁的青春不迷茫", "心之所向"); 16 } 17 } 18 19 /*运行结果 : 20 谁的青春不迷茫 21 心之所向 22 56*/
- 在最后一个形参类型后加 ... ,则表明该形参可以接受多个参数值
- 长度可变形参在一个方法中最多只能有一个,而且只能放在最后
7. Java的函数重载
- 函数名相同,形参列表不同(至于其他部分,函数返回值、修饰符部分与函数重载无关)
- 不能用函数返回值来区别函数重载
- 不建议重载含有可变形参的函数,这样没有意义而且容易产生歧义
8. 成员变量和局部变量:
- 成员变量
- 实例属性(不以static修饰)
- 类属性(以static修饰)
- 局部变量
- 形参(方法签名中定义的变量)
- 方法局部变量(在方法内定义)
- 代码块局部变量(在代码块内定义)
- 与成员变量不同的是,局部变量除形参外均需要显性初始化(否者使用会出错)不
9. super是直接父类的默认引用(super其实就是直接负累的this,故其也不能出现在静态方法中)
10. Java中的多态
-
1 public class Person 2 { 3 public String name; 4 private int age; 5 6 7 Person(){ 8 this.name = "Person name"; 9 } 10 11 Person(String name){ 12 this.name = name; 13 } 14 15 public int getAge(){ 16 return age; 17 } 18 19 public void setAge(int age){ 20 this.age = age; 21 } 22 23 public String getName(){ 24 return name; 25 } 26 27 public void setName(String name){ 28 this.name = name; 29 } 30 } 31 32 33 34 public class Student extends Person 35 { 36 public String name; 37 private String love; 38 39 Student(){ 40 this.name = "Student Name"; 41 love = "Robbin"; 42 } 43 44 public String getName(){ 45 return this.name; 46 } 47 48 public String getLove(){ 49 return love; 50 } 51 } 52 53 54 public class TestPolymorphism 55 { 56 public static void main(String[] args) 57 { 58 Person s = new Student(); 59 60 //编译时类型是Person, 运行时类型是Student, 编译时只能调用编译类型的方法,否则报错 61 //System.out.println(s.getLove()); 62 /*TestPolymorphism.java:7: 错误: 找不到符号 63 System.out.println(s.getLove()); 64 ^ 65 符号: 方法 getLove() 66 位置: 类型为Person的变量 s 67 1 个错误*/ 68 69 //将Peron引用变量(实际指向一个Student对象),向下转型为Student类的引用变量后就可以访问getLove()方法了 70 Student ss = (Student)s; 71 System.out.println(ss.getLove()); 72 73 Person p = new Person(); 74 //此判断为判断p能否转型为Student对象 75 if(p instanceof Student){ 76 //运行下面语句会发生运行时错误,原因是一个Person对象不能转型为其子类对象Student(注:向下转型能成功的条件是父类引用指向的对象就是目标类引用类型) 77 Student sss = (Student)p; 78 System.out.println(sss.getLove()); 79 }else{ 80 System.out.println("Can not cast!!"); 81 } 82 /*Exception in thread "main" java.lang.ClassCastException: Person cannot be cast to Student 83 at TestPolymorphism.main(TestPolymorphism.java:20)*/ 84 85 //用父类引用调用getName,实际执行的是子类的方法(体现了多态) 86 System.out.println(s.getName()); 87 88 //由于类的属性不具备多态性,故用Person引用变量访问的name是Peron里的,而不是Student里的 89 System.out.println(s.name); 90 } 91 } 92 93 /* 94 1. 引用变量只能调用申明该变量时所用的类里所包含的方法; 95 2. 与方法不同的是对象的属性不具备多态性; 96 3. 通过引用变量来访问其包含的实例属性时,系统总是试图访问它编译时类所定义的属性,而不是它运行时累所定义的属性 97 4. 强制类型转换应注意: 98 a.基本类型之间的转换只能在数值类型之间 99 b.引用类型之间的转换只能把一个父类变量转换成子类类型(向下转型),且需要具备继承关系 100 */ 101 102 103 /* 104 运行结果: 105 Robbin 106 Student Name 107 Person name 108 */
11. 累属性和类成员属于类,在加载类时就已经分配内存空间,,故对于该类的引用,即便其值为null,也能访问类成员和类方法 -
1 public class Person 2 { 3 public String name; 4 private int age; 5 public static int armNumber = 2; 6 7 Person(){ 8 this.name = "Person name"; 9 } 10 11 Person(String name){ 12 this.name = name; 13 } 14 15 public int getAge(){ 16 return age; 17 } 18 19 public void setAge(int age){ 20 this.age = age; 21 } 22 23 public String getName(){ 24 return name; 25 } 26 27 public void setName(String name){ 28 this.name = name; 29 } 30 31 public static int getArmNumber(){ 32 return armNumber; 33 } 34 } 35 36 37 38 public class Test1 39 { 40 public static void main(String[] args) 41 { 42 Person p = null; 43 System.out.println(p.armNumber); 44 System.out.println(p.getArmNumber()); 45 } 46 } 47 48 49 50 /* 51 运行结果: 52 2 53 2 54 请按任意键继续. . . 55 */
12. Java的单例化类:
1 class Singleton 2 { 3 //使用一个变量来缓存曾经创建的实例 4 private static Singleton instance; 5 6 //将构造器使用private修饰,隐藏该构造器 7 private Singleton(){} 8 9 //提供一个方法,用于返回Singleton实例 10 //该方法可以加入自定义控制,保证只产生一个Singleton对象 11 public static Singleton getInstance(){ 12 13 //如果instance为null则生成一个Singleton对象并储存起来 14 if(instance == null){ 15 instance = new Singleton(); 16 } 17 return instance; 18 } 19 } 20 21 public class TestSingleton{ 22 public static void main(String[] args){ 23 Singleton s1 = Singleton.getInstance(); 24 Singleton s2 = Singleton.getInstance(); 25 26 //本语句会打印出true, 说明s1和s2所指向的是同一个对象,两个引用的值是一样的(即Singleton只实例化了一次) 27 System.out.println(s1 == s1); 28 } 29 }
13. Java final:
- final修饰变量时,表示该变量一旦获得初始值之后就不可改变
- final修饰成员变量:
- 类属性:可在静态初始化块中、申明该属性时指定初始值
- 实例属性:可在非静态初始化块、申明该属性、构造器中指定初始值
- 需要注意的是不要重复初始化,如果某个实例属性已经在初始化块中初始化就不能再在构造器中初始化(因为final修饰的变量一旦获得初始值之后就不可改变)
- 与普通成员变量不同的是final修饰的成员变量只能显示初始化,系统不会对其进行隐式初始化
-
1 public class Test{ 2 final int age; 3 { 4 //系统不会对final修饰的成员属性进行默认初始化,所以此处代码将会报错 5 System.out.println(age); 6 7 age = 6; 8 System.out.println(age); 9 } 10 11 public static void main(String[] args){ 12 new Test(); 13 } 14 }
-
- final修饰局部变量:
- 系统不会对局部变量进行初始化,局部变量必须由程序员显式初始化
- final修饰的局部变量可以在定义时指定默认值,这样在之后的操作中就不能对该变量进行修改
- final修饰的局部变量在定义时若没有指定默认值,则在之后的操作中只能对其赋值一次,不能重复赋值
- final修饰基本类型和引用类型的区别
- final修饰基本类型时本能重新赋值,因此不能改变(若在编译时就可以确定具体的值,则可当作常量来处理,要符合常量命名规范=>每个单词字母都要大写,单词之间用下划线分割开。eg. PUBLIC_STATIC_INSTANCE)
- final修饰引用类型时其保存的地址不能变,即其只能指向唯一的一个对象,但对象的具体内容可以改变
- final方法
- final修饰的方法不可被重写
- final修饰的private方法在子类中可以出现相同方法名,相同形参列表,相同返回值的函数(因为这样不是重写,private修饰的方法也不会被重写,这样定义只是在子类中多了一个新方法而已)
- final修饰的方法只是不能被重写而已,并不是不能被重载
Test1:
-
1 class Person 2 { 3 final public void test(){} 4 } 5 6 class Student extends Person 7 { 8 public void test(){} 9 } 10 11 12 13 public class TestFinal 14 { 15 public static void main(String[] args) 16 { 17 System.out.println("Hello World!"); 18 } 19 } 20 21 22 /* 23 TestFinal.java:9: 错误: Student中的test()无法覆盖Person中的test() 24 public void test(){} 25 ^ 26 被覆盖的方法为final 27 1 个错误 28 请按任意键继续. . . 29 */
Test2:
1 class Person 2 { 3 final public void test(){} 4 //这样编译通过 5 final public void test(String arg){} 6 7 final private void test2(){ System.out.println("Person test2!!");} 8 } 9 10 class Student extends Person 11 { 12 //public void test(){} 13 14 //允许这样定义,这样并不是重写父类的函数 15 public void test2(){ System.out.println("Student test2!!!");} 16 } 17 18 19 20 public class TestFinal 21 { 22 public static void main(String[] args) 23 { 24 Person p = new Student(); 25 p.test2(); 26 } 27 } 28 29 /* 30 TestFinal.java:26: 错误: test2()可以在Person中访问private 31 p.test2(); 32 ^ 33 1 个错误 34 请按任意键继续. . . 35 36 标注:说明执行的还是父类的方法,test2方法并没有被Student类重写,因此没有多态性 37 */
-
final修饰的类不可以被继承
-
不可变类:
- 属性都是由final private 修饰, 只能提供getter方法,而不能提供setter方法
- 提供带参构造器,用于根据传入参数初始化属性的值
- 如果有必要要重写equal和hashCode方法
- 注意:如果某个不可变类的一个属性是可变类,则其getter方法不能直接返回该属性(因为返回该引用之后就能对该引用指向对象的内容进行修改,这样就不能保证这是一个不可变类了),应该new一个新的对象(这个属性的新对象,而不是这个不可变类 的新对象),将这个属性copy一份仔返回
- 缓存实例的不可变类:
-
1 public class CacheImmutale 2 { 3 private final String name; 4 private static CacheImmutale[] cache = new CacheImmutale[10]; 5 //记录缓存实例在缓存中的位置,cache[pos - 1]是最新缓存的实例 6 private static int pos = 0; 7 8 public CacheImmutale(String name){ 9 this.name = name; 10 } 11 12 public String getName(){ 13 return name; 14 } 15 16 public static CacheImmutale valueOf(String name){ 17 //遍历已缓存对象 18 for(int i = 0; i < 10; i++){ 19 //如果已有相同实例,直接返回该缓存实例 20 if(cache[i] != null && cache[i].getName().equals(name)){ 21 return cache[i]; 22 } 23 } 24 25 //如果缓存池已满 26 if(pos == 10){ 27 //把缓存的第一个对象覆盖,即把刚刚生成的对象放在缓存池最开始的位置 28 cache[0] = new CacheImmutale(name); 29 //把pos设为1 30 pos = 1; 31 return cache[0]; 32 }else{ 33 //把新建的对象缓存起来,pos加一 34 cache[pos++] = new CacheImmutale(name); 35 return cache[pos - 1]; 36 } 37 } 38 39 public boolean equals(Object obj){ 40 if(obj instanceof CacheImmutale){ 41 CacheImmutale ci = (CacheImmutale)obj; 42 if(name.equals(ci.getName())){ 43 return true; 44 } 45 } 46 return false; 47 } 48 49 50 public int hashCode(){ 51 return name.hashCode(); 52 } 53 54 public static void main(String[] args){ 55 CacheImmutale c1 = CacheImmutale.valueOf("hello"); 56 CacheImmutale c2 = CacheImmutale.valueOf("hello"); 57 58 //以下语句将会输出true 59 System.out.println(c1 == c2); 60 61 62 Integer i1 = Integer.valueOf(5); 63 Integer i2 = Integer.valueOf(5); 64 //以下语句将会输出true(八个封装类也是用一样的方式实现的缓存) 65 System.out.println(i1 == i2); 66 } 67 }
-
-
-
八个基本数据类型的封装类通过valueOf的方式创建的实例也是通过类似的方法缓存的
-
缓存有利有弊,如果这个类对象要被重复创建,则缓存利大于弊
-