java基礎知識-基本概念


1.1 java語言有哪些優點?

1.java語言為純面向對象的語言。

2.平台無關性。java語言的優點便是“一次編譯,到處執行”。編譯后的程序不會被平台所約束,因此java語言有很好的移植性。

3.java提供了許多內置的類庫,將代碼封裝好來給操作人員使用,從而大大減少開發人員的時間。

4.提供了對web應用的開發的支持。

5.具有較好的安全性和健壯性。

6.去除了c++語言中難以理解,容易混淆的特性,例如頭文件,指針,結構,單元運算符重載,虛擬基礎類,多重繼承等,所以java語言是由c++語言改進並重新設計而來的

1.2 java語言和c/c++有什么異同。

java和C++都是面向對象的語言,都使用了面向對象的思想(例如封裝,繼承,多態),由於面向對象有許多非常好的特性(繼承,組合等),因此二者都有很好的重用性。

下面重點說一下不同點:

1.java為解釋型語言,c/c++為編譯型語言,java代碼由java編譯器編譯成字節碼,然后由JVM解釋,C語言代碼經過編譯和鏈接生成可執行的二進制代碼,因此java的執行速度比c++慢,但是java可跨平台執行,c/c++不能

2.java語言沒有指針

3.java只能實現單重繼承,但是可以引入多個接口

4.java為純面向對象語言,所有代碼必須在類里實現

5.java語言提供了垃圾回收器來實現對垃圾的自動回收,c++語言中需要開發人員去管理對內存的分配。C語言,通常會把釋放資源的代碼放在析構函數中,Java沒有但是有finalize()方法。

java語言不支持運算符重載,C語言支持

java不支持默認函數參數,c語言支持

java不提供goto語句,c/c++支持,但是在java中goto為保留關鍵字

java不支持自動強制類型裝換,c語言支持

java具有平台無關性,就是對每種數據類型分配固定長度。

java提供對注釋文檔的內建支持

java包含了一些標准庫

1.3 為什么使用public static void main(String[] args)方法?

main是程序的入口方法,所以程序執行時第一個執行的方法就是main方法。

main()方法定義的其他幾種格式:

1.static pubic void main(String[] args)

static 和public無先后順序

2.public static final void main(String[] args)

可以定義為final

3.static public synchronized void main(String[] args)

可以定義為synchronized

不管哪種定義方式,必須保證main()方法類型為void並且有static和public關鍵字修飾。不可以用abstract關鍵字,因為main()為程序的入口方法。

1.4靜態塊

靜態塊會在類被加載時調用,可以在main()方法前執行

例如:

public class jingtaikuai {

public static void main(String[] args) {
System.out.println("hello word");
}
static{
System.out.println("靜態塊");
}

}

執行結果:

靜態塊 hello word

1.5 java程序初始化順序是怎樣的

java程序的初始化一般遵循三個原則(優先級依次遞減):

1.靜態對象優先於非靜態對象

2.父類優先於子類

3.按照成員變量定義順序進行初始化

常見面試題:

下面代碼的運行結果是什么?

class B extends Object{
static {
System.out.println("load b1");
}
public B(){
System.out.println("create b");
}
static{
System.out.println("load b2");
}
}
class A extends B{
static {
System.out.println("load a");
}
public A(){
System.out.println("create a");
}
}
public class 初始化順序 {
public static void main(String[] args) {
new A();
}

}

執行結果:

load b1 load b2 load a create b create a

1.6 java作用域

在Java語言中,變量的類型主要有3種:成員變量、靜態變量和局部變量

首先說靜態變量跟局部變量

靜態變量不依賴於特定的實例,而是被所有實例共享,也就是說,只要一個類被加載,JVM就會給類的靜態變量分配

存儲空間。因此可以通過類名.變量名來訪問靜態變量

局部變量的作用域與可見性為它所在的花括號內

類的成員變量的作用范圍同類的實例化對象的作用范圍相同。當類被實例化的時候,成員變量就會在內存中分配空間,並初始化。

直到類的實例化對象的生命周期結束時,成員變量的生命周期才結束。

作用域與可見性 當前類 同一package 子類 其他package
public
private × × ×
protected ×
default × ×

重點說一下protected和default:

protected:表名成員變量或方法對該類自身,與它在同一個包中的其他類,在其他包中的該類的子類都可見

default:表明該成員變量或方法只有自己和與其位於同一包內的類可見。

若父類與子類處於同一包內,則子類對父類的default成員變量或方法都有訪問權限;若父類與子類處於不同的package內,則沒有訪問權限


還有需要注意的是,這些修飾符只能修飾成員變量,不能修飾局部變量。

private和protected不能用來修飾類

1.7 一個java文件中能否定義多個類

一個java文件中可以定義多個類,但是最多只能有一個類被public修飾,並且這個類的類名必須和文件名相同。

1.8 java的構造函數

一、什么是構造函數

java構造函數,也叫構造方法,是java中一種特殊的函數。函數名與相同,無返回值。

作用:一般用來初始化成員屬性和成員方法的,即new對象產生后,就調用了對象了屬性和方法。

在現實生活中,很多事物一出現,就天生具有某些屬性和行為。比如人一出生,就有年齡、身高、體重、就會哭;汽車一出產,就有顏色、有外觀、可以運行等。這些,我們就可以將這些天然的屬性和行為定義在構造函數中,當new實例化對象時,也就具有這些屬性和方法了,沒必要再去重新定義了,從而加快了編程效率。

構造函數是對象一建立就運行,給對象初始化,就包括屬性,執行方法中的語句。

而一般函數是對象調用才執行,用".方法名“的方式,給對象添加功能。

一個對象建立,構造函數只運行一次。

而一般函數可以被該對象調用多次。

 

二、構造函數的特點

1、函數名與類名相同

2、不用定義返回值類型。(不同於void類型返回值,void是沒有具體返回值類型;構造函數是連類型都沒有)

3、不可以寫return語句。(返回值類型都沒有,也就不需要return語句了

注:一般函數不能調用構造函數,只有構造函數才能調用構造函數。

三、示例

1、無參構造函數中只定義了一個方法。new對象時,就調用與之對應的構造函數,執行這個方法。不必寫“.方法名”。

package javastudy;

public class ConfunDemo {
   public static void main(String[] args) {
       Confun c1=new Confun();            //輸出Hello World。new對象一建立,就會調用對應的構造函數Confun(),並執行其中的println語句。
  }
}
class Confun{        
   Confun(){        //定義構造函數,輸出Hello World
       System.out.println("Hellow World");
  }
}

輸出:Hellow World

 

2、有參構造函數,在new對象時,將實參值傳給private變量,相當於完成setter功能。

package javastudy;

public class ConfunDemo3 {
   public static void main(String[] args){
       Person z=new Person("zhangsan",3);        //實例化對象時,new Person()里直接調用Person構造函數並轉轉實參,相當於setter功能
       z.show();
  }
}

class Person{
   private String name;
   private int age;
   public Person(String n,int m){                //有參數構造函數,實現給private成員變量傳參數值的功能
       name=n;
       age=m;        
  }
   //getter                                     //實例化對象時,完成了sett功能后,需要getter,獲取實參值。
   public String getName(){
       return name;
  }
   public int getAget(){
       return age;
  }
   public void show(){                           //獲取private值后,並打印輸出
       System.out.println(name+"\n"+age);
  }
}

輸出: zhangsan 3

以上代碼,我們也可以將show()方法中的輸出語句直接放在構造函數中,new對象時,即可直接輸出值,如下

package javastudy;

public class ConfunDemo3 {
   public static void main(String[] args){
       Person z=new Person("zhangsan",3);        //實例化對象時,new Person()里直接調用Person構造函數並轉轉實參,同時執行輸出語句
  }
}

class Person{
   private String name;
   private int age;
   public Person(String n,int m){                //有參數構造函數,實現給private成員變量傳參數值的功能,同時直接輸出值
       name=n;
       age=m;
       System.out.println(name+"\n"+age);
  }
}

輸出: zhangsan 3

class ConFun
{
   public static void main(String[] args){
       Person z=new Person(20,"zhangsan");
       System.out.println(z.getAge()+z.getName());
  }
}

class Person
{
   private int age;
   private String name;
   public Person(int x,String y){
       age=x;
       name=y;
  }
   public int getAge(){
       return age;
  }
   public String getName(){
       
       return name;
  }
}

3、一個對象建立后,構造函數只運行一次

如果想給對象的值再賦新的值,就要使用set和get方法,此時是當做一般函數使用

如下:

package javastudy;

public class ConfunDemo4 {
   public static void main(String[] args) {
           PersonDemo s=new PersonDemo("李三",33);        //new對象時,即調用對應的構造函數,並傳值。同時,不能new同一個對象多次,否則會報錯。
           s.setName("李五");                            //對象建立后,想變更值時,就要用set/get方法,重新設置新的值
           s.setName("阿爾法狗");                        //並可調用對象多次。
           s.print();
  }
}
class PersonDemo{
   private String name;
   private int age;
   PersonDemo(String n,int m){                //建立有參構造函數,用於給兩個private變量name、age賦值,同時輸出值
       name=n;
       age=m;
       System.out.println("姓名:"+name+"年齡:"+age);
  }
   public void setName(String x){            //set方法,用於再次給name賦值
       name=x;        
  }
   public String getName(){                //get方法,用於獲取name的賦值
       return name;
  }
   public void print(){
       System.out.println(name);
  }
}

輸出結果:

姓名:李三年齡:33 阿爾法狗

 

 

四、默認構造函數

當一個類中沒有定義構造函數時,系統會給該類中加一個默認的空參數的構造函數,方便該類初始化。只是該空構造函數是隱藏不見的。

如下,Person(){}這個默認構造函數是隱藏不顯示的。

class Person
{  
   //Person(){}
}

當在該類中自定義了構造函數,默認構造函數就沒有了。

如果仍要構造函數,則需要自己在類中手動添加。

 

五、構造函數的重載

構造函數也是函數的一種,同樣具備函數的重載(Overloding)特性。

class Person
{  
   private String name;
   private int age;

   Person()
  {
       System.out.println("A:name="+name+":::age="+age);
  }

   Person(String n)
  {
       name = n;
       System.out.println("B:name="+name+":::age="+age);
  }

   Person(String n,int a)
  {  
       name=n;
       age=a;
       System.out.println("C:name="+name+":::age="+age);
  }

}

class PersonDemo2
{
   public static void main(String[] args)
  {
       Person p1=new Person();
       Person p2=new Person("lishi");
       Person p3=new Person("lishi",10);
  }
}

輸出結果: A:name=null:::age=0 B:name=lishi:::age=0 C:name=lishi:::age=10

class Person
{  
   private String name;
   private int age;

   Person()
  {
       System.out.println("A:name="+name+":::age="+age);
       cry();
  }

   Person(String n)
  {
       name = n;
       System.out.println("B:name="+name+":::age="+age);
       cry();
  }

   Person(String n,int a)
  {  
       name=n;
       age=a;
       System.out.println("C:name="+name+":::age="+age);
       cry();

  }
   void cry()
  {
       System.out.println("Cry...............");
  }

}

class PersonDemo2
{
   public static void main(String[] args)
  {
       Person p1=new Person();
       Person p2=new Person("lishi");
       Person p3=new Person("lishi",10);
  }
}

輸出結果: A:name=null:::age=0 Cry............... B:name=lishi:::age=0 Cry............... C:name=lishi:::age=10 Cry...............

轉自:http://www.cnblogs.com/ibelieve618/p/6364541.html

1.9 java中的clone方法

java中所有的類都繼承自Object類,這個類提供了一個clone的方法,這個方法的作用是返回一個Object對象的復制。

使用步驟:

1.繼承Cloneable 接口

2.重寫clone()方法

3.clone方法中調用super.clone()

4.把淺復制的引用指向原型對象新的克隆體


一、簡單用法

只需要在需要clone的對象上實現(implements)Cloneable接口,然后再在類中加上clone方法,在方法中只需要調用super.clone(),根據自己的需要實現即可。

public class Student implements Cloneable {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}

@Override
protected Student clone() throws CloneNotSupportedException {
return (Student)super.clone();
}

public static void main(String[] args) {
Student stu = new Student();
stu.setAge(1);
stu.setName("aa");
System.out.println(stu + " age: " + stu.getAge() + " name: " + stu.getName());
try {
Student sC = stu.clone();
System.out.println(sC + " sC.age: " + sC.getAge() + " sC.name: " + sC.getName());
sC.setAge(12);
sC.setName("bb");
System.out.println(stu + " age: " + stu.getAge() + " name: " + stu.getName());
System.out.println(sC + " sC.age: " + sC.getAge() + " sC.name: " + sC.getName());
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}

輸出結果:

testClone.Student@15db9742 age: 1 name: aa testClone.Student@6d06d69c sC.age: 1 sC.name: aa testClone.Student@15db9742 age: 1 name: aa testClone.Student@6d06d69c sC.age: 12 sC.name: bb

分析結果:1、根據輸出結果中前邊的類名,可以得出被克隆對象的與原來的對象是同一種類型。2、根據內存地址(hashcode)知道,被克隆對象的與原來的對象是存在於內存中的不同的兩個對象。所以后邊有一個賦值,對原來對象沒有任何影響。

二、“影子”克隆與深度克隆

首先看一個例子:

class Bag{//學生的書包
private int width;
private String logo;
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public String getLogo() {
return logo;
}
public void setLogo(String logo) {
this.logo = logo;
}
}

public class Student2 implements Cloneable {
private String name;
private int age;
private Bag bag;

public Bag getBag() {
return bag;
}
public void setBag(Bag bag) {
this.bag = bag;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}

@Override
protected Student2 clone() throws CloneNotSupportedException {
return (Student2)super.clone();
}

public static void main(String[] args) {
Student2 stu = new Student2();
stu.setAge(1);
stu.setName("aa");
Bag b = new Bag();
b.setWidth(10);
b.setLogo("Nike");
stu.setBag(b);
printStudent(stu);
try {
Student2 sC = stu.clone();
printStudent(sC);
sC.setAge(12);
sC.setName("bb");
sC.getBag().setWidth(100);//改變書包的屬性
sC.getBag().setLogo("JNike");
printStudent(stu);
printStudent(sC);
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

/**
* 輸出
* @param stu
*/
private static void printStudent(Student2 stu) {
System.out.println(stu + " age: " + stu.getAge() + " name: " + stu.getName() +
" bag: " + stu.getBag() + "(" + stu.getBag().getLogo() + " width: " +
stu.getBag().getWidth() + ")");
}

} 輸出結果: testClone.Student2@15db9742 age: 1 name: aa bag: testClone.Bag@6d06d69c(Nike width: 10) testClone.Student2@7852e922 age: 1 name: aa bag: testClone.Bag@6d06d69c(Nike width: 10) testClone.Student2@15db9742 age: 1 name: aa bag: testClone.Bag@6d06d69c(JNike width: 100) testClone.Student2@7852e922 age: 12 name: bb bag: testClone.Bag@6d06d69c(JNike width: 100)

分析:發現是不是跟預期的不太一樣,通過第二個同學改變書包,但是第一個同學的書包也被改變了。並且通過內存地址可知,他們是同一對象(書包)。原因:調用Object類中clone()方法產生的效果是:先在內存中開辟一塊和原始對象一樣的空間,然后原樣拷貝原始對象中的內 容。對基本數據類型,這樣的操作是沒有問題的,但對非基本類型變量,我們知道它們保存的僅僅是對象的引用,這也導致clone后的非基本類型變量和原始對 象中相應的變量指向的是同一個對象。 這就是所謂的“影子”克隆。

解決方案:深度克隆,既是對里邊的引用也要克隆。以下是實現:

class Bag implements Cloneable{//學生的書包
private int width;//寬
private String logo;//品牌
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public String getLogo() {
return logo;
}
public void setLogo(String logo) {
this.logo = logo;
}

@Override
protected Bag clone() throws CloneNotSupportedException {
return (Bag)super.clone();
}

}

public class Student3 implements Cloneable {
private String name;
private int age;
private Bag bag;

public Bag getBag() {
return bag;
}
public void setBag(Bag bag) {
this.bag = bag;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}

@Override
protected Student3 clone() throws CloneNotSupportedException {
Student3 stu = (Student3)super.clone();
stu.bag = bag.clone();
return stu;
}

public static void main(String[] args) {
Student3 stu = new Student3();
stu.setAge(1);
stu.setName("aa");
Bag b = new Bag();
b.setWidth(10);
b.setLogo("Nike");
stu.setBag(b);
printStudent(stu);
try {
Student3 sC = stu.clone();
printStudent(sC);
sC.setAge(12);
sC.setName("bb");
sC.getBag().setWidth(100);//改變書包的屬性
sC.getBag().setLogo("JNike");
printStudent(stu);
printStudent(sC);
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

/**
* 輸出
* @param stu
*/
private static void printStudent(Student3 stu) {
System.out.println(stu + " age: " + stu.getAge() + " name: " + stu.getName() +
" bag: " + stu.getBag() + "(" + stu.getBag().getLogo() + " width: " +
stu.getBag().getWidth() + ")");
}

}

輸出: testClone.Student3@15db9742 age: 1 name: aa bag: testClone.Bag@6d06d69c(Nike width: 10) testClone.Student3@7852e922 age: 1 name: aa bag: testClone.Bag@4e25154f(Nike width: 10) testClone.Student3@15db9742 age: 1 name: aa bag: testClone.Bag@6d06d69c(Nike width: 10) testClone.Student3@7852e922 age: 12 name: bb bag: testClone.Bag@4e25154f(JNike width: 100)

1.10 什么是反射機制

Java 反射機制是在運行狀態中,對於任意一個類,都能夠獲得這個類的所有屬性和方法,對於任意一個對象都能夠調用它的任意一個屬性和方法。這種在運行時動態的獲取信息以及動態調用對象的方法的功能稱為Java 的反射機制。

Class 類與java.lang.reflect 類庫一起對反射的概念進行了支持,該類庫包含了Field,Method,Constructor類(每個類都實現了Member 接口)。這些類型的對象時由JVM 在運行時創建的,用以表示未知類里對應的成員。

這樣你就可以使用Constructor 創建新的對象,用get() 和set() 方法讀取和修改與Field 對象關聯的字段,用invoke() 方法調用與Method 對象關聯的方法。另外,還可以調用getFields() getMethods() 和 getConstructors() 等很便利的方法,以返回表示字段,方法,以及構造器的對象的數組。這樣匿名對象的信息就能在運行時被完全確定下來,而在編譯時不需要知道任何事情。

二、獲取字節碼的方式

在Java 中可以通過三種方法獲取類的字節碼(Class)對象

  • 通過Object 類中的getClass() 方法,想要用這種方法必須要明確具體的類並且創建該類的對象。

  • 所有數據類型都具備一個靜態的屬性.class 來獲取對應的Class 對象。但是還是要明確到類,然后才能調用類中的靜態成員。

  • 只要通過給定類的字符串名稱就可以獲取該類的字節碼對象,這樣做擴展性更強。通過Class.forName() 方法完成,必須要指定類的全限定名,由於前兩種方法都是在知道該類的情況下獲取該類的字節碼對象,因此不會有異常,但是Class.forName() 方法如果寫錯類的路徑會報 ClassNotFoundException 的異常。

    ackage com.jas.reflect;

    public class ReflectTest {
       public static void main(String[] args) {

           Fruit fruit = new Fruit();
           Class<?> class1 = fruit.getClass();     //方法一

           Class<?> class2 = Fruit.class;     //方法二

           Class class3 = null;    
           try {    //方法三,如果這里不指定類所在的包名會報 ClassNotFoundException 異常
               class3 = Class.forName("com.jas.reflect.Fruit");
          } catch (ClassNotFoundException e) {
               e.printStackTrace();
          }

           System.out.println(class1 + " " +class2 + "   " + class3);

      }
    }

    class Fruit{}

 

三、通過反射機制獲取類信息

通過反射機制創建對象,在創建對象之前要獲得對象的構造函數對象,通過構造函數對象創建對應類的實例。

下面這段代碼分別在運行期間創建了一個無參與有參的對象實例。由於getConstructor() 方法與newInstance() 方法拋出了很多異常(你可以通過源代碼查看它們),這里就簡寫了直接拋出一個Exception,下同。

復制代碼

package com.jas.reflect;

import java.lang.reflect.Constructor;

public class ReflectTest {
   public static void main(String[] args) throws Exception {

       Class clazz = null;
       clazz = Class.forName("com.jas.reflect.Fruit");
       Constructor<Fruit> constructor1 = clazz.getConstructor();
       Constructor<Fruit> constructor2 = clazz.getConstructor(String.class);

       Fruit fruit1 = constructor1.newInstance();
       Fruit fruit2 = constructor2.newInstance("Apple");

  }
}

class Fruit{
   public Fruit(){
       System.out.println("無參構造器Run...........");
  }
   public Fruit(String type){
       System.out.println("有參構造器Run..........." + type);
  }

}

輸出: 無參構造器Run……….. 有參構造器Run………..Apple

通過反射機制獲取Class 中的屬性

package com.jas.reflect;

import java.lang.reflect.Field;

public class ReflectTest {
   public static void main(String[] args) throws Exception {

       Class<?> clazz = null;
       Field field = null;

       clazz = Class.forName("com.jas.reflect.Fruit");
       //field = clazz.getField("num");       getField() 方法不能獲取私有的屬性
       // field = clazz.getField("type");     訪問私有字段時會報 NoSuchFieldException異常
       field = clazz.getDeclaredField("type");     //獲取私有type 屬性
       field.setAccessible(true);  //對私有字段的訪問取消檢查
       Fruit fruit = (Fruit) clazz.newInstance();  //創建無參對象實例
       field.set(fruit,"Apple");   //為無參對象實例屬性賦值
       Object type = field.get(fruit); //通過fruit 對象獲取屬性值

       System.out.println(type);
  }
}

class Fruit{
   public int num;
   private String type;

   public Fruit(){
       System.out.println("無參構造器Run...........");
  }
   public Fruit(String type){
       System.out.println("有參構造器Run..........." + type);
  }

}

輸出: 無參構造器Run……….. Apple

通過反射機制獲取Class 中的方法並運行。

package com.jas.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class ReflectTest {
   public static void main(String[] args) throws Exception {

       Class clazz = null;
       Method method = null;

       clazz = Class.forName("com.jas.reflect.Fruit");
       Constructor<Fruit> fruitConstructor = clazz.getConstructor(String.class);
       Fruit fruit = fruitConstructor.newInstance("Apple");    //創建有參對象實例

       method = clazz.getMethod("show",null);  //獲取空參數show 方法
       method.invoke(fruit,null);  //執行無參方法

       method = clazz.getMethod("show",int.class); //獲取有參show 方法
       method.invoke(fruit,20);  //執行有參方法

  }
}

class Fruit{
   private String type;

   public Fruit(String type){
       this.type = type;
  }
   public void show(){
       System.out.println("Fruit type = " + type);
  }
   public void show(int num){
       System.out.println("Fruit type = " + type + ".....Fruit num = " + num);
  }
}

輸出: Fruit type = Apple Fruit type = Apple…..Fruit num = 20

四、反射機制簡單應用(使用簡單工廠創建對象)

Class.forName() 生成的結果是在編譯時不可知的,因此所有的方法特征簽名信息都是在執行時被提取出來的。反射機制能過創建一個在編譯期完全未知的對象,並調用該對象的方法。

以下是反射機制與泛型的一個應用,通過一個工廠類創建不同類型的實例。

要創建對象的實例類Apple :

package com.jas.reflect;

public interface Fruit {}
class Apple implements Fruit{}

加載的配置文件config.properties:

Fruit=com.jas.reflect.Apple

工廠類BasicFactory :

package com.jas.reflect;

import java.io.FileReader;
import java.util.Properties;

public class BasicFactory {
   private BasicFactory(){}

   private static BasicFactory bf = new BasicFactory();
   private static Properties pro = null;

   static{
       pro = new Properties();
       try{    
           //通過類加載器加載配置文件
           pro.load(new FileReader(BasicFactory.class.getClassLoader().
                   getResource("config.properties").getPath()));
      }catch (Exception e) {
           e.printStackTrace();
      }
  }

   public static BasicFactory getFactory(){
       return bf;
  }

   //使用泛型獲得通用的對象
   public  <T> T newInstance(Class<T> clazz){
       String cName = clazz.getSimpleName();   //獲得字節碼對象的類名
       String clmplName = pro.getProperty(cName);   //根據字節碼對象的類名通過配置文件獲得類的全限定名

       try{
           return (T)Class.forName(clmplName).newInstance();   //根據類的全限定名創建實例對象
      }catch (Exception e) {
           throw new RuntimeException(e);
      }

  }
}

創建對象實例:

package com.jas.reflect;

public class ReflectTest {
   public static void main(String[] args) throws Exception {
       Fruit fruit = BasicFactory.getFactory().newInstance(Fruit.class);
       System.out.println(fruit);
  }
}

輸出 com.jas.reflect.Apple@4554617c

上面這個實例通過一個工廠創建不同對象的實例,通過這種方式可以降低代碼的耦合度,代碼得到了很大程度的擴展,以前要創建Apple 對象需要通過new 關鍵字創建Apple 對象,如果我們也要創建Orange 對象呢?是不是也要通過new 關鍵字創建實例並向上轉型為Fruit ,這樣做是麻煩的。

現在我們直接有一個工廠,你只要在配置文件中配置你要創建對象的信息,你就可以創建任何類型你想要的對象,是不是簡單很多了呢?可見反射機制的價值是很驚人的。

Spring 中的 IOC 的底層實現原理就是反射機制,Spring 的容器會幫我們創建實例,該容器中使用的方法就是反射,通過解析xml文件,獲取到id屬性和class屬性里面的內容,利用反射原理創建配置文件里類的實例對象,存入到Spring的bean容器中。

參考書籍: 《Java 編程思想》 Bruce Eckel 著 陳昊鵬 譯

1.10 java創建對象的幾種方式

  1. 通過new實例化一個對象

  2. 通過反射機制創建對象

  3. 通過clone方法創建一個對象

  4. 通過反序列化方式創建一個對象

1.11 package作用

package的作用

  • package的中文意思是“包”,它是一個比較抽象的邏輯概念,其宗旨是把.java文件 (Java源文件)、.class文件(編譯后的文件)以及其他resource文件(例如.xml文件、.avi文件、.mp3文件、.txt文件等)有條理地進行一個組織,以供使用。它類似於Linux文件系統, 有一個根,從根開始有目錄和文件,然后目錄中嵌套目錄。

  • 具體而言,package主要有以下兩個作用: 第一,提供多層命名空間,解決命名沖突,通過使用package,使得處於不同package中的類可以存在相同的名字。 第二,對類按功能進行分類,使項目的組織更加清晰。當開發一個有非常多的類的項目時,如果不使用package對類進行分類,而是把所有類都放在一個package下,這樣的代碼不僅可讀性差,而且可維護性也不好,會嚴重影響開發效率。

2)package的用法

  • package的用法一般如下(源文件所在目錄為當前目錄): 1.在每個源文件的開頭加上"package packagename;",然后源文件所在目錄下創建一個新目錄,名稱為 packapename。 2.用javac指令編譯每個sourcename. java源文件,將生成的sourcename. classname文件復制到packagename 目錄。 3.用 java 指令運行程序:java packagename. sourcename。

3)實例 以下是一個簡單的程序示例。

package top.itcourse.pkg;

public class TestPackage {
   public static void main(String[] args) {
       System.out.println("Hello World!");
  }
}

結果: Hello World!




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM