當程序要使用某個類時,若是該類還未被加載到內存中,則系統會經過加載,鏈接,初始化三步來實現對這個類進行初始化。java
加載服務器
就是指將class文件讀入內存,併爲之建立一個Class對象。oracle
任何類被使用時系統都會創建一個Class對象tcp
在class文件進入方法和數據共享區時,在執行Main方法和靜態成員變量/方法以前,會爲class文件在堆裏面建立一個「文件對象」,又叫字節碼對象(不是new Person())!學習
鏈接this
驗證 是否有正確的內部結構,並和其餘類協調一致spa
準備 負責爲類的靜態成員分配內存,並設置默認初始化值.net
解析 將類的二進制數據中的符號引用替換爲直接引用code
這個時候才輪到靜態區,靜態方法靜態成員賦初值!server
初始化
就是咱們之前講過的初始化步驟
類初始化時機
1. 建立類的實例
2. 類的靜態變量,或者爲靜態變量賦值
3. 類的靜態方法
4. 使用反射方式來強制建立某個類或接口對應的java.lang.Class對象
5. 初始化某個類的子類
6. 直接使用java.exe命令來運行某個主類
類加載器
負責將.class文件加載到內存中,併爲之生成對應的Class對象。
雖然咱們不須要關心類加載機制,可是瞭解這個機制咱們就能更好的理解程序的運行
類加載器的組成
Bootstrap ClassLoader 根類加載器
也被稱爲引導類加載器,負責Java核心類的加載
好比System,String等。在JDK中JRE的lib目錄下rt.jar文件中
Extension ClassLoader 擴展類加載器
負責JRE的擴展目錄中jar包的加載。
在JDK中JRE的lib目錄下ext目錄
System ClassLoader 系統類加載器
負責在JVM啓動時加載來自java命令的class文件,以及classpath環境變量所指定的jar包和類路徑。
經過反射獲取構造方法並使用
在反射機制中,把類中的成員(構造方法、成員方法、成員變量)都封裝成了對應的類進行表示。其中,構造方法使用類Constructor表示。可經過Class類中提供的方法獲取構造方法:
返回一個構造方法
public Constructor<T> getConstructor(Class<?>... parameterTypes) 獲取public修飾, 指定參數類型所對應的構造方法
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 獲取指定參數類型所對應的構造方法(包含私有的)
返回多個構造方法
public Constructor<?>[] getConstructors() 獲取全部的public 修飾的構造方法
public Constructor<?>[] getDeclaredConstructors() 獲取全部的構造方法(包含私有的)
經過反射獲取成員變量並使用
在反射機制中,把類中的成員變量使用類Field表示。可經過Class類中提供的方法獲取成員變量:
返回一個成員變量
public Field getField(String name) 獲取指定的 public修飾的變量
public Field getDeclaredField(String name) 獲取指定的任意變量
返回多個成員變量
public Field[] getFields() 獲取全部public 修飾的變量
public Field[] getDeclaredFields() 獲取全部的 變量 (包含私有)
經過反射獲取成員方法並使用
在反射機制中,把類中的成員方法使用類Method表示。可經過Class類中提供的方法獲取成員方法:
返回獲取一個方法:
public Method getMethod(String name, Class<?>... parameterTypes)
獲取public 修飾的方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
獲取任意的方法,包含私有的
參數1: name 要查找的方法名稱; 參數2: parameterTypes 該方法的參數類型
返回獲取多個方法:
public Method[] getMethods() 獲取本類與父類中全部public 修飾的方法
public Method[] getDeclaredMethods() 獲取本類中全部的方法(包含私有的)
示例代碼:
package com.oracle.filetcp; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class TCPClient { public static void main(String[] args) throws UnknownHostException, IOException { Socket soc=new Socket("127.0.0.1",7001); //寫到服務器用的流: OutputStream out=soc.getOutputStream(); //讀取本地文件: FileInputStream fis=new FileInputStream("F:\\IOTest\\TestPic.jpg"); int len=0; byte[] bytes=new byte[1024]; //若是從文件裏面讀,是有文件末尾的,若是從流裏面去讀,是沒有文件末尾的,沒有-1,因此read方法會發生阻塞! while((len=fis.read(bytes))!=-1){ out.write(bytes,0,len); } //告訴服務器到這裏已經結束了,已經到末尾了! soc.shutdownOutput(); //接收服務器端的回覆: InputStream in=soc.getInputStream(); len=in.read(bytes); System.out.println(new String(bytes,0,len)); //釋放資源: fis.close(); soc.close(); } } package com.oracle.filetcp; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class TCPServer { public static void main(String[] args) throws IOException { //明確端口號: ServerSocket server=new ServerSocket(9999); //該方法接收客戶端返回過阿里的Socket對象: Socket soc=server.accept(); //服務器客戶端之間的輸入流,明確數據源: InputStream in=soc.getInputStream(); //明確目的地: File file=new File("F:\\IOTest\\Test"); if(!file.exists()){ file.mkdirs(); } //寫文件: FileOutputStream fos=new FileOutputStream(file+"\\TestPic0601.jpg"); //開始複製: int len=0; byte[] bytes=new byte[1024]; while((len=in.read(bytes))!=-1){ fos.write(bytes,0,len); } //回覆客戶端: OutputStream out=soc.getOutputStream(); out.write("上傳成功".getBytes()); //釋放資源: server.close(); fos.close(); } } package com.oracle.filetcp; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class UPLoad implements Runnable { private Socket soc; public UPLoad(Socket soc){ this.soc=soc; } public void run(){ FileOutputStream fos=null; try{ //服務器客戶端之間的輸入流,明確數據源: InputStream in=soc.getInputStream(); //明確目的地: File file=new File("F:\\IOTest\\Test"); if(!file.exists()){ file.mkdirs(); } //寫文件: fos=new FileOutputStream(file+"\\TestPic0601.jpg"); //開始複製: int len=0; byte[] bytes=new byte[1024]; while((len=in.read(bytes))!=-1){ fos.write(bytes,0,len); } //回覆客戶端: OutputStream out=soc.getOutputStream(); out.write("上傳成功".getBytes()); }catch(IOException ex){ ex.printStackTrace(); }finally{ //釋放資源: try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } package com.oracle.filetcp; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class TestUPLoad { public static void main(String[] args) throws IOException { ServerSocket server=new ServerSocket(7001); while(true){ Socket soc=server.accept(); new Thread(new UPLoad(soc)).start(); } } } package com.oracle.filetcp; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class TCPClient { public static void main(String[] args) throws UnknownHostException, IOException { Socket soc=new Socket("127.0.0.1",7001); //寫到服務器用的流: OutputStream out=soc.getOutputStream(); //讀取本地文件: FileInputStream fis=new FileInputStream("F:\\IOTest\\TestPic.jpg"); int len=0; byte[] bytes=new byte[1024]; //若是從文件裏面讀,是有文件末尾的,若是從流裏面去讀,是沒有文件末尾的,沒有-1,因此read方法會發生阻塞! while((len=fis.read(bytes))!=-1){ out.write(bytes,0,len); } //告訴服務器到這裏已經結束了,已經到末尾了! soc.shutdownOutput(); //接收服務器端的回覆: InputStream in=soc.getInputStream(); len=in.read(bytes); System.out.println(new String(bytes,0,len)); //釋放資源: fis.close(); soc.close(); } } package com.oracle.filetcp; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class TCPServer { public static void main(String[] args) throws IOException { //明確端口號: ServerSocket server=new ServerSocket(9999); //該方法接收客戶端返回過阿里的Socket對象: Socket soc=server.accept(); //服務器客戶端之間的輸入流,明確數據源: InputStream in=soc.getInputStream(); //明確目的地: File file=new File("F:\\IOTest\\Test"); if(!file.exists()){ file.mkdirs(); } //寫文件: FileOutputStream fos=new FileOutputStream(file+"\\TestPic0601.jpg"); //開始複製: int len=0; byte[] bytes=new byte[1024]; while((len=in.read(bytes))!=-1){ fos.write(bytes,0,len); } //回覆客戶端: OutputStream out=soc.getOutputStream(); out.write("上傳成功".getBytes()); //釋放資源: server.close(); fos.close(); } }
如下代碼是利用反射讀取配置文件,實現不修改代碼只修改Properties文件實現修改功能:
package com.oracle.fanshelast; public class Person { public void eat(){ System.out.println("人吃飯"); } } package com.oracle.fanshelast; public class Student { public void study(){ System.out.println("學生學習"); } } package com.oracle.fanshelast; public class Worker { public void work(){ System.out.println("工人工做"); } } //Properties配置文件: #className=com.oracle.fanshelast.Person #methodName=eat className=com.oracle.fanshelast.Worker methodName=work //Main方法主代碼: package com.oracle.fanshelast; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Properties; public class Test { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //new Person().eat(); //反射配置文件實現修改代碼: //把咱們要運行的類和方法以鍵值對的形式寫在文本中,咱們想要運行哪一個類,裏面的方法只須要改配置文件便可! //步驟: /*準備配置文件 IO讀取配置文件Reader 將文件中的鍵值對保存在咱們所學的Properties集合中鍵值對就是類和方法名 經過反射獲取指定類的Class文件對象 經過Class文件對象獲取指定方法 運行方法*/ FileReader fr=new FileReader("src/Config.properties"); Properties pro=new Properties(); pro.load(fr); String className=pro.getProperty("className"); String methodName=pro.getProperty("methodName"); //這裏傳的是上方String className的值,即Properties文件中的鍵值對的值! Class cal=Class.forName(className); Object obj=cal.newInstance(); Method met=cal.getMethod(methodName); met.invoke(obj); } }