Java基礎加強_MyEclipse、JDK1.5新特性、枚舉、反射

Java基礎加強---day01

一、MyEclipse的使用技巧

    Eclipse和MyEclipse:MyEclipse本來是Eclipse的一個插件,增加了java ee項目的開發功能。但安裝了Eclipse還要安裝插件,很麻煩;於是MyEclipse廠商就把Eclipse包含進來,並提供一個默認的JRE,一鍵安裝即可。

    IDE:IDE是集成開發環境,支持使用工程化方式管理一個項目的程序開發過程,一般來說,一個相對獨立的項目就是一個工程,一個項目中涉及的多個java文件,資源文件等用一個工程進行管理。在不使用工程管理的情況下,如果一個項目中包括多個Java源文件,編程人員需要精心維護這些源文件之間、以及源文件與其它文件的目錄關係,需要逐一編譯這些源文件,需要手工啓動運行編譯後的結果。如果將一個程序的所有源文件用一個工程來組織,開發工具能對所有源文件集中管理,記住每個源文件的位置和相互關係。工程中有哪幾個源文件、啓動類是哪個、啓動參數設置等配置信息在工程中都記錄。

    一個Workspace(工作區)可以包含多個Project(工程),一個Workspace保留了Eclipse的一套環境變量的配置。

    一個Perspective代表了若干個View的集合,可以通過window-->show view-->選擇需要的View;

    可以手動配置編譯和運行環境:window-->preference-->java-->compiler(或者Installed JREs);注意:高版本編譯出來的字節碼交給低版本的JRE運行,會出現錯誤。

    導入已有的工程:先把要導入的工程copy到Workspace文件目錄下,然後:import-->Existing  Projects into Workspace,確認即可。導入的工程後,有可能工程原來所用的JRE與Workspace中的JRE不一致,導致一些編譯運行錯誤。這時可以點擊右鍵,buildPath-->configure  buildPath,先刪除已有的JRE庫,再增加原來的JRE庫,即可。

    怎樣調試一個變量的值?雙擊一行,觀察到左邊出現斷點,右鍵debug  as,切換到調試視圖下,選中變量右鍵watch,單步運行即可。

    註釋整個段落的內容:先選中要註釋的內容,然後ctr+shift+/;

    當類文件或者某個字段的名稱寫錯時,可以重構:右鍵refactor-->rename,即可。

    設置單個工程的javac和java,選擇工程,右鍵->properties可以設置javac,右鍵->run as-->open rundialog可以設置java。

    內容助理:alt+/;單行註釋:ctr+/;多行註釋:ctr+shift+/。

    代碼模板的設置:java-->editor-->Templates。

二、JDK1.5的幾個新特性

    2.1、靜態導入:import static

    import語句可以導入一個類或者某個包中的所有類;

    import  static語句可以導入一個類中的某個靜態方法或者所有的靜態方法。導入後可以直接寫方法名,不用註明類名;但靜態導入的多個類中有相同的靜態方法,需要註明方法的類名。

    2.2、可變參數

    當一個方法接收的參數不固定時,在JDK1.4版本之前,用一個數組存儲這些參數;在1.5版本之後,用可變參數(…)的形式。其實可變參數內部還是封裝了一個數組,只不過是編譯器隱式幫助創建一個數組罷了;注意:可變參數必須出現在參數列表的末尾。

    2.3增強for循環

    格式:for(type 變量名:集合變量名){…};

    被遍歷的集合變量要麼是數組,要麼是集合,增強for循環只能對集合中的元素進行遍歷,不能進行增刪改等的操作。建議平時使用普通for循環,因爲可以操作角標。這個升級:簡化書寫。

2.4基本數據類型的自動裝箱和自動拆箱

    自動拆箱與自動裝箱:發生在八種基本數據類型和所對應的包裝類之間的自動轉換動作。

享元模式:flyweight,當整數在一個字節大小內時,使用享元模式,即在內存中使用的是同一個對象。

三、枚舉

    枚舉:枚舉就是讓某個類型的變量的取值只能是若干個固定值中的一個,否則,編譯器會報錯。枚舉可以讓編譯器在編譯時期就可以控制源程序中填寫的非法值,普通變量的方式在開發階段無法實現這一目標。枚舉也是JDK1.5的一個新特性。

    用普通類實現枚舉功能的方法:1、私有化構造方法;2、每個元素用一個公有的靜態成員變量表示;3、可以定義一些抽象方法,然後每個枚舉的元素用匿名內部類的形式實現該抽象方法

    enum:枚舉有enum關鍵字表示,相當於一個類,其中也可以定義構造方法、成員變量、普通方法、抽象方法等等。

    注意:枚舉元素必須位於枚舉體中的最開始部分,枚舉元素列表的最後要有分號與其他成員分隔。在枚舉中的構造方法必須私有化;枚舉中可以帶有抽象的方法,抽象方法可以交給枚舉元素分別取實現,使用匿名內部類的形式。

下面代碼體現:

1、用一個星期類模擬枚舉

package itheima.day07;

//模擬枚舉的類
public abstract  class Weekday {
	
//	1、私有化構造函數,外界不能創建對象
	private Weekday(){}
	
//	2、向外提供該類的實例
	public final static Weekday SUN = new Weekday(){
		public Weekday nextday(){
			return MON;
		}
	};
	public final static Weekday MON = new Weekday(){
		public Weekday nextday(){
			return SUN;
		}
	};
	
//	在類中定義了抽象方法,那麼該類也是抽象類,
//	可以讓實例對象通過匿名內部類的形式實現這些抽象方法
	public abstract Weekday nextday();
	
//	覆蓋繼承於Object類的toString方法
	@Override
	public String toString() {
		if(this ==SUN)
			return "SUN";
		else
			return "MON";
	}	
}

2、星期、交通燈的枚舉形式

package itheima.day07;

public class EnumTest {

	public static void main(String[] args) {
		
//		Weekday wd1 = Weekday.SUN;
//		System.out.println(wd1.nextday());	
//		Weekday wd2 = Weekday.MON;
//		System.out.println(wd2.nextday());
		
//		使用星期的枚舉類
		Weekday1 wd1 =Weekday1.MON;
		Weekday1 wd2 = Weekday1.SUN;
		
//		使用交通燈的枚舉類
		TrafficLamp red = TrafficLamp.RED;
		System.out.println(red);
		System.out.println(red.nextLamp());
//		名稱
		System.out.println(red.name());
//		秩序
		System.out.println(red.ordinal());
		System.out.println(red.valueOf("RED").toString());
		System.out.println(red.values().length);
	}
	
//	爲了讓權限爲public,不同包中也可以訪問,
//	但一個源文件中不能有兩個類爲public權限,所以使用內部類的形式
	public enum TrafficLamp{
//		枚舉的元素
		 RED(30){
			@Override
			public TrafficLamp nextLamp() {
				return GREEN;
			} 
		 },
		 GREEN(45){
			@Override
			public TrafficLamp nextLamp() {
				return YELLOW;
			}	 
		 },
		 YELLOW(5){
			@Override
			public TrafficLamp nextLamp() {
				return RED;
			}	 
		 };
		 
//		 枚舉中的抽象方法,交給實例對象去實現
		public abstract  TrafficLamp nextLamp();
		
//		枚舉的構造方法可以自定義,但必須是private權限,其實枚舉就是一個特殊的類
		private int time;
		private TrafficLamp(int time){
			this.time = time;
		}
	}
//	星期的枚舉
	public	enum Weekday1{
		SUN(1),MON;
		private Weekday1(){
			System.out.println("first");
		}
		private Weekday1(int day){
			System.out.println("second");
		}
	}
}

四、反射

    4.1、Class類

    Person類代表人,它的實例對象可以是張三、李四等等這樣具體的人。同理:Class類描述的是內存中的字節碼,每一份字節碼都是Class類在內存中的一個具體對象

    獲取Class類對象、即具體的一份字節碼的方法:

        1、類名.class;例如:System.class;

        2、對象.getClass(),例如:new Stirng(“abc”).getClass();

        3、Class.forName(“類名”),例如:Class.forName(“java.lang.String”);

    每一種不同的類型,都有對應的字節碼,同一種類型在內存中使用的是同一份字節碼。

例如:int、double、int[]、int[][]、void等等都有對應的字節碼。

注意:每一個類在內存中的字節碼唯一!

    4.2、反射

    反射:反射就是把java類中的各個成分映射成爲相應的java類。例如,一個Java類中用一個Class類的對象來表示,一個類中的組成部分:成員變量,方法,構造方法,包等等信息也用一個個的Java類來表示,就像汽車是一個類,汽車中的發動機,變速箱等等也是一個個的類。表示java類的Class類顯然要提供一系列的方法,來獲得其中的變量,方法,構造方法,修飾符,包等信息,這些信息就是用相應類的實例對象來表示,它們是Field、Method、Contructor、Package等等。

    4.3、Constructor類

    Constructor類:代表某一份字節碼中的構造方法

    獲取全部構造函數:Constructor[] constructors =

        Class.forName(“java.lang.String”).getConstructors();

    獲取某一個構造函數:Constructor constructor =

        Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);

    獲取到一份字節碼中的構造函數後,就可以用這些構造函數創建具體的實例對象了,

        例如:constructor.newInstance(new StringBuffer(“abc”));注意:構造函數的參數列表的類型必須一致,否則運行出錯。

    一般是先獲取具體的一份字節碼,然後再獲取該字節碼中的構造函數,之後才能用該構造函數去創建對象;爲了簡化過程,可以使用字節碼直接創建對象(只能創建默認無參的);

    例如:Class.newInstance()方法:

        Stringobj =(String)Class.forName(“java.lang.String”).newInstance();

    該方法內部先得到默認的構造方法,然後用該構造方法創建實例對象,緩存機制。

    4.4、Field類

    Field類:代表某一份字節碼中的成員變量。注意:得到的只是一份字節碼中的某個成員變量字段,並非具體對象的那個成員變量字段。具體的操作會在代碼中說明。

    4.5、Method類

    Method類:代表的是某一份字節碼中的成員方法。關於main方法的反射、數組的反射等都在接下來的代碼中詳細說明,在此不再細說。

    4.6、反射的作用

    反射的作用:實現框架功能。因爲框架往往是先寫成,寫的時候要調用的那些類還沒存在,所以只能使用反射,將特定的類名傳入到框架中,即可。

    框架:專門調用別人的類,提高效率的工具。注意:框架是調用用戶提供的類,而工具類被用戶的類調用。

    Java中有內存泄露嗎?有;比如當把對象存入到hashSet集合中時,改變了hashSet集合中對象的hashcode值;要知道,contains/remove、equals方法的底層都是調用hashcode和equals方法的,這時就會存在內存泄露,所以應該禁止改變已經存入hashSet集合中的hashcode值。

    getRealPath()可以獲取到軟件項目的安裝路徑,可以加上內部的路徑,就是絕對路徑了,confige配置文件的絕對路徑一般這樣獲得。

    一般將配置文件放在classpath路徑下,但myEclipse能把src源文件路徑下的配置文件在編譯時複製到classpath路徑下,所以可以把配置文件放在源文件下;

    類加載器可以將類的字節碼加載進內存,也可以將配置文件順帶加進內存。

下面代碼體現:

3、演示反射的基本類:

package itheima.day07;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

//演示反射的基本類
public class ReflectTest {

	public static void main(String[] args) throws Exception{
		String str1 ="abc";
//		獲取字節碼
		Class clazz1 = str1.getClass();
		Class clazz2 = String.class;
		Class clazz3 = Class.forName("java.lang.String");
		
//		一個類在內存中的字節碼唯一
		System.out.println(clazz1 ==clazz3);
		
		System.out.println(clazz1.isPrimitive());
		System.out.println(int.class.isPrimitive());
		System.out.println(int.class == Integer.class);
		System.out.println(int.class == Integer.TYPE);
		
//		獲取構造方法
		Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
		
//		用反射獲取到的字節碼創建對象
		String str2 = (String) constructor1.newInstance(new StringBuffer("abcdefg"));
		
		System.out.println(str2.toUpperCase());
		
		ReflectPoint pt1 = new ReflectPoint(3, 5);
//		獲取類中的一個字段
		Field fieldY = pt1.getClass().getField("y");
//		類中的字段與相應的對象相關聯
		System.out.println(fieldY.get(pt1));
		
//		暴力反射私有字段
		Field fieldX = pt1.getClass().getDeclaredField("x");
		fieldX.setAccessible(true);
		
		System.out.println(fieldX.get(pt1));
		
//		改變字符串的某一個值
		changeStrValue(pt1);
		System.out.println(pt1);
		
//		獲取類中的方法
		Method methodCharAt = String.class.getMethod("charAt", int.class);
		System.out.println(methodCharAt.invoke(str1, 1));
		
//		關於main方法的反射
		String startingClassName = args[0];
		Method mainMethod =
				Class.forName(startingClassName).getMethod("main", String[].class);
		mainMethod.invoke(null, new Object[]{new String[]{"aaa","bbb","ccc"}});
		
//		數組類型的字節碼
		int[] a1 =new int[]{1,2,3};
		int[] a2 =new int[4];
		int[][] a3 =new int[2][3];
		String[] a4 =new String[]{"aaa","bbb","ccc"};
		
		System.out.println(a1.getClass() ==a2.getClass());//true
//		以下兩端代碼編譯都通不過,更加說明了 每種類型在內存中的字節碼唯一
//		System.out.println(a1.getClass() ==a3.getClass());
//		System.out.println(a1.getClass() ==a4.getClass());
		
		Object aObj1 = a1;
		Object aObj2 = a4;
		Object[] aObj4 = a3;
		Object[] aObj5 =a4;
		
//		用數組工具類Arrays把一個數組轉換成爲一個List集合
//		當數組中的元素是基本數據類型時,那麼整個數組看做是一個List元素
		System.out.println(Arrays.asList(a1));
//		非基本數據類型時,數組中的每個元素看做是一個List元素
		System.out.println(Arrays.asList(a4));
		
//		該方法就是彌補上面方法的不足!
		printObject(a1);
		printObject(a4);
	}
	private static void printObject(Object obj) {
//		既然是反射,那麼先獲取字節碼
		Class clazz = obj.getClass();
		
//		如果字節碼是數組類型的話,拆分
		if(clazz.isArray()){
			int len = Array.getLength(obj);
			for(int i=0;i<len;i++){
				System.out.println(Array.get(obj, i));
			}
		}else{
			System.out.println(obj);
		}
	}
//	利用反射的方式改變一個類的某些字符字段中的字母
	private static void changeStrValue(ReflectPoint pt1) throws IllegalArgumentException, IllegalAccessException {
		Field[] fields = pt1.getClass().getFields();
		
		for(Field field:fields){
			if(field.getType() ==String.class){
				String oldValue =(String) field.get(pt1);
				String newValue = oldValue.replace('b', 'a');
				field.set(pt1, newValue);
			}
		}
	}
}
演示反射main方法的類:
package itheima.day07;

public class MainReflectTest {

	public static void main(String[] args) {
		for(String arg:args){
			System.out.println(arg);
		}
	}
}

演示反射的類:
package itheima.day07;

public class ReflectPoint {
	
	private int x;
	public int y;
	
	public String str1 = "ball";
	public String str2 = "basketball";
	public String str3 ="itcast";
	
//	構造方法
	public ReflectPoint(int x,int y){
		this.x =x;
		this.y =y;
	}
	
//	getter and setter
	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}
	
//	複寫toString方法,不然打印的東西看不懂
	@Override
	public String toString() {
		return "str1::"+str1+"  ,str2::"+str2+" ,str3::"+str3;
	}
}
4、反射的演示2
package itheima.day01;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Properties;

public class ReflectTest2 {

	public static void main(String[] args) throws IOException, InstantiationException, IllegalAccessException, ClassNotFoundException {
		
//		記住用完整的路徑,不是硬編碼,而是運算出來的
//		InputStream ips = new FileInputStream("config.properties");
	
//		用類加載器的形式加載配置文件
//		InputStream ips = 
//			ReflectTest2.class.getClassLoader().getResourceAsStream("itheima/day01/config.properties");
//		相對路徑,文件放在包的resource文件夾下
		InputStream ips = ReflectTest2.class.getResourceAsStream("resource/config.properties");
		

//		IO流與Map結合的一個重要工具類
		Properties props = new Properties();
//		加載
		props.load(ips);
//		關閉流
		ips.close();
//		獲取類名
		String className = props.getProperty("className");
//		根據類名創建一個集合類,反射!
		Collection collection = (Collection)Class.forName(className).newInstance();
		
		ReflectPoint pt1 = new ReflectPoint(3,3);
		ReflectPoint pt2 = new ReflectPoint(5,5);
		ReflectPoint pt3 = new ReflectPoint(3,3);
		
		collection.add(pt1);
		collection.add(pt2);
		collection.add(pt3);
		collection.add(pt1);
		
		System.out.println(collection.size());
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章