1.构造器与初始化
创建对象时,如果没有显性的创建构造器,则jvm会创建一个默认的无参构造器,如果创建了构造器,那么jvm将不在创建构造器。
构造器:与类名相同,无返回值。
public class Construct { public static void main(String[] args) { Rock r = new Rock(); Rock1 r1 = new Rock1(); Rock2 r2 = new Rock2(11); } } //默认构造器 class Rock {} //手动添加无参构造器 class Rock1 { public Rock1() { System.out.println("无参构造"); } } //有参构造器 class Rock2{ public Rock2(int i){ System.out.println(i); } }
2.方法重载
方法重载:指方法名相同,参数列表不同。如有参构造与无参构造,即为方法重载。不能以返回值区分是否为重载方法。
2.1基本类型的方法重载:
所传参数类型与方法类型相同,则调用与之匹配的方法。
所传参数类型小于方法中参数类型,则匹配与之容量最近的方法,char类型比较特殊,char类型作为参数传递,会默认提升为int类型
所传参数类型大于方法中参数类型,则需将所传参数类型进行强制转换,否则编译不通过。
3.this关键字
如果想在方法内部获得当前对象可使用this关键字,this关键字只能存在于方法内部,表示当前对对象的引用。
3.1 方法内部调用this:可以直接return this返回当前对象
3.2 构造函数调用
public class Flower { public static void main(String[] args) { Worker wk = new Worker("玫瑰",999);//输出结果,先输出"无花之人",在输出"采了999花",最后输出"采了999玫瑰花" } } class Worker{ Worker(){ System.out.println("无花之人"); } Worker(int i){ this(); System.out.println("采了"+i+"花"); } Worker(String name,int i){ this(i); System.out.println("采了"+i+name+"花"); } }
调用构造函数时,会根据this()传递的参数,自动匹配含有对应参数的构造函数。
4.static关键字
static修饰静态变量或方法,在创建对象前就已经被创建,且只存在一份,不能调用非static修饰的变量或方法,不存在this关键字,不需要创建对象。
5.清理及垃圾回收。
5.1finalize的用途,一旦垃圾回收准备好释放对象占用的存储空间,将首先调用finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象点用的内存。
public class FinizeTest { public static void main(String[] args) { new FinalizeCase(); System.gc(); } } class FinalizeCase{ protected void finalize() throws Throwable { super.finalize(); System.out.println("执行了垃圾回收"); } }
重写finalize方法,调用父类的finalize(),当只是通过new FinalizeCase()创建对象时,并没有引用指向对象,此时等着垃圾回收来回收此对象,但是垃圾回收发生是不定时的,无法控制,故我们通过调用System.gc()方法强制进行垃圾回收,通过输出可以看到,finalize()方法执行了。所以我们不能全指望垃圾回收处理,当某些必须关闭回收的对象,我们可以自己书写代码进行关闭。
5.2 垃圾回收原理
其它系统中的垃圾回收:每个对象者含有一个引用计数器,当对象有引用连接时,引用计数器加1,当对象无引用连接时,则计数器减1,直至减少为0,则该对象就将会被回收。
java虚拟机采用一种更自适应的垃圾回收技术,对于查找活的对象,通过停止-复制、标记-清扫方法进行。
标记-清扫:指从堆栈和静态存储区出发,遍历所有的引用,进行找出所有存活的对象,每当找到一个存活的对象,就会给对象进行一个标记,这个过程不会对回收任何对象,只有全部标记工作完成的时候,清理动作才会开始,在清理过程中,没有标记的对象不会被复制,直接释放空间,所以剩下的堆空间是不连续的,如果要得到连续的空间,则需要进行重新整理。
停止-复制:指拉圾回收器进行工作时,程序将停止运行,然后将活的对象复制到另一片区域中去,且按顺序进行排列,将变量引用指向新地址,此种方法复制需要更大的内存区域,效率比较低下。
6.成员初始化
对象中成员初始化:如果存在静态变量,则先初始化静态变量,然后初始化成员变量,在进行构造函数初始化。如果存在继承关系,首先初始化父类静态变量,在初始化子类静态变量,在初始化父类成员变量,在进行父类构造函数初始化,在初始化子类成员变量,子类构造函数初始化。
1.成员初始化
public class OrderInitialization { public static void main(String[] args) { House house = new House();//输出首先执行属性初始化,即先创建窗户1,然后在窗户2,在窗户3,在执行构造函数 } } class Window{ Window(int i){ System.out.println("window:("+i+")"); } } class House{ Window w1= new Window(1); House(){ System.out.println("this is house"); Window w3 = new Window(3); } Window w2 = new Window(2); Window w3 = new Window(3); }
2.静态数据实始化
静态数据实始化:先执行静态成员变量实始化,且静态成员只会执行一次,在执行实例化成员,在执行构造函数。
3.显示静态实初始化
多个含有static关键字的子名:静态成员,静态块执行根据书写顺序执行,且一旦静态成员被访问,则其它静态成员同样会被初始化。
public class StaticInit { public static void main(String[] args) { Table table = new Table(); System.out.println("***************"); Table table1 = new Table(); /** 输出如下,静态成员只执行一次 cup(1) cup(2) cup(3) table cup(33) *************** cup(3) table cup(33) * */ } } class Cup{ Cup(int i){ System.out.println("cup("+i+")"); } } class Table{ static Cup cup1 = new Cup(1); Cup cup3 = new Cup(3); Table(){ System.out.println("table"); cup3 = new Cup(33); } static Cup cup2 = new Cup(2); }
4.初始化块,对象中通过{}包裹需要执行的方法,每创建一个对象 ,就会执行一次初始化块中代码
public class InitBlock { private String name; private String price; { System.out.println( "name = 华为"); System.out.println( " price=4000"); } public static void main(String[] args) { InitBlock ib = new InitBlock(); InitBlock ib1 = new InitBlock(); /**输出 name = 华为 price=4000 name = 华为 price=4000 */ } }
5.父子类初始化顺序
public class FatherAndSonInit { public static void main(String[] args) { Son son = new Son(); } //父子类初始化顺序,父类static,子类static,父类成员实始化,父类构造函数,子类成员初始化,子类构造函数 /**输出结果 * father static:Peple--父类静态 * Son static:Peple -- 子类静态 * father man :man -- 父类成员变量 * father --父类构造函数输出 * Son man:man -- 子类成中变量 * Son -- 子类构造函数输出 */ } class Peple1{ Peple1(String s){ System.out.println(s+":Peple"); } } class Man{ Man(String s){ System.out.println(s+":man"); } } class Father{ static Peple1 p1 = new Peple1("father static"); Father(){ System.out.println("father"); } Man m = new Man("father man "); } class Son extends Father{ static Peple1 p1 = new Peple1("Son static"); Son(){ System.out.println("Son"); } Man m = new Man("Son man"); }
7.数组初始化
public static void main(String[] args) { int[] i = new int[6]; String[] s = new String[]{"one","tow","three"}; double[] d = {1d,2d,3d,4d}; for (int i1 : i) { System.out.println(i1);//第一种方式创建,未给初始值,默认为0,如果引用类型,则默认为null } }
数组中存入的是对象的引用,如果存入的是基本数据类型,则对应的会得到基本数据类型对应的初始值。
8.可变参数
public static void main(String[] args) { testVar(new String[]{"one","tow","three"},13,new Integer[]{1,2,3,4,5}); } public static void testVar(Object... args){ for (Object arg : args) { System.out.println(arg); } }
可变参数的基本形式为(数据类型... args),表示传递不定多个形式参数,如果需要传递固定多个形式参数,则需要将固定的形式参数放至参数前边。
9.枚举
public enum EnumTest { NOT,MILD,MEDIUM,HOT,FLAMING; public static void main(String[] args) { //可以直接调用 System.out.println(EnumTest.FLAMING); //可以获得其下标和具体的内容 for (EnumTest enumTest : EnumTest.values()) { System.out.println(enumTest.ordinal()+":"+enumTest); /** 输出 0:NOT 1:MILD 2:MEDIUM 3:HOT 4:FLAMING */ } } }
基本用法如上,可以定义某些常量,然后直接调用其结果
用法二:
public enum EmunCalss { BEIJIN("001"),SHANGHAI("021"),GUANGDONG("020"),CQINGQING("023"); private String value; EmunCalss(String value){ this.value = value; } public static void main(String[] args) { for (EmunCalss emunCalss : EmunCalss.values()) { System.out.println("name:"+emunCalss.name()+", value:"+emunCalss.value); } /**输出,定义的前边部位为name,可以在枚举中定义一个变量,得其值 name:BEIJIN, value:001 name:SHANGHAI, value:021 name:GUANGDONG, value:020 name:CQINGQING, value:023 */ } }