1.當eclipse項目改變了編譯配置(項目右鍵屬性Properties->Java Compiler),用了高版本的編譯器編譯,則用低版本的JVM運行會報錯,彈窗JVM啓動警告Could not find the main class.Program will exit,報class文件的版本號錯誤java.lang.UnsupportedClassVersionError:Bad version number in .class file。
解決辦法:
降低編譯器版本。
升高運行版本。(項目右鍵屬性Properties->Java Build Path->Libraries添加高版本jre)
2.斷點:
F5:step into 跳入
F6:step over 跳過
F7:step return跳出
drop to frame:跳到當前方法的第一行
resume:跳到下一個斷點(如果沒有下一個,則運行完整個程序)
右鍵watch:觀察變量或表達式的值
斷點注意的問題:
1.斷點調試完成後,要在breakpoints視圖中清除所有斷點
2.斷點調試完成後,一定要記得結束運行斷點的jvm
3.常用快捷鍵:
ctrl + shift + L : 查看所有快捷鍵
alt + / : 內容助理
ctrl + 1: 快速修復
ctrl + shift +o : 導包
ctrl + shift +F : 格式化代碼塊
ctrl + 左鍵 / F3:查看代碼中存在方法,類的源代碼
ctrl + shirt + T :查看指定類的源代碼
Alt + 左/右:查看源代碼的時候,回到上一步/下一步
ctrl + shift + / : 添加註釋 /**/
ctrl + shift + \: 除去註釋 /**/
F2 :查看方法說明
重置透視圖(windows save/reset)
ctrl + shift + X :大寫
ctrl + shift + Y :小寫
ctrl + alt + 向上/下鍵:複製行
alt + 向上/下鍵:移動行
ctrl + T : 查看繼承關係
ctrl +m : 窗口最大化/還原
ctrl +f :查找替換
ctrl + shift + L 查看所有快捷鍵
4.junit測試框架:在測試方法前加@Test
1.每個測試方法之前都運行:(常用)
@Before + 方法前: 初始化資源
@After + 方法前: 釋放資源
2.類加載的時候運行,只運行一次: 方法必須設置靜態static的
@BeforeClass + 方法前:作用同上
@AfterClass + 方法前:
3.斷言類:判斷返回值
import static org.junit.Assert.*;
assertEquals("返回值錯誤!","2", p.run());
5.JDK1.5新特性:
1.靜態導入:導入類的靜態成員,方便程序簡化書寫。
2.自動裝箱拆箱:
int num = 4;
num = num + 5;
Integer i =4; //等效,Integer i = new Integer(4); 自動裝箱,就是簡化書寫。
//自動裝箱和不同賦值相比,多了一個空null。
//所以要先判斷是否爲null。因爲空類型在拆箱的時候會報空指針異常。
i = i + 6; //等效i = new Integer(i.intValue() + 6); 自動裝箱,拆箱(i.intValue())。
show(55);
public static void show(Object a){ //Object a = new Ingeter(55); 裝箱,多態
}
面試:自定裝箱,如果裝箱的是一個字節,那麼該數據會被共享,不會重新開闢空間。
Integer a = new Integer(127);
Integer b = new Integer(127);
System.out.println(a==b); //false
System.out.println(a.equals(b)); //true
Integer x = 127;
Integer y = 127;
System.out.println(x==y); //true, 自定裝箱,如果裝箱的是一個字節,那麼該數據會被共享,不會重新開闢空間。
System.out.println(x.equals(y)); //true
public class Demo1 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(127); //裝箱
list.add(127);
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next()==it.next()); //true,超過一個字節就是false
}
}
}
3.增強for循環
JDK1.5給Collection接口找了個父接口Iterable,實現這個接口允許對象成爲 “foreach” 語句的目標。
foreach語句:底層還是實現的迭代。
格式:
for(類型 變量: Collection集合|數組)
{
}
傳統for和高級for的區別:
foreach侷限性:
必須有遍歷的目標(數組或Collection單列集合),一般只用於遍歷,不會對元素進行過多的操作。是用來簡化書寫的。
傳統for循環相對foreach的優勢:
可以定義控制循環的條件和增量。
使用場景:
對數組的遍歷如果僅僅是獲取數組中的元素,可以使用foerach。
如果要對數組的角標進行操作建議使用傳統for。
對於map集合,不能直接使用foreach遍歷。但是可以將map轉換成單列的set,就可以用了。
例子:
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<String,Integer>();
map.put("小米", 2000);
map.put("蘋果", 5000);
map.put("三星", 4000);
//entrySet:
Set<Map.Entry<String, Integer>> entrySet = map.entrySet(); //map變成set集合
for (Map.Entry<String, Integer> entry : entrySet) { //foreach遍歷
System.out.println(entry.getKey() + ":" +entry.getValue());
}
//keySet:
for(String key : map.keySet()){
Integer value = map.get(key);
System.out.println(key + ": " + value);
}
//傳統迭代:
Iterator<Map.Entry<String,Integer>> it= map.entrySet().iterator();
while(it.hasNext()){
Map.Entry<String, Integer> me = it.next();
System.out.println(me.getKey() + ":" + me.getValue());
}
}
4.可變參數:int …
內部執行的動作:創建並將參數封裝成數組。
其實就是一個數組,但是接收的是數組的元素。
自動將這些元素封裝成數組。簡化了調用者的書寫。
注意事項:可變參數類型必須定義在參數列表的結尾處。
//求多個正數的和
public static void main(String[] args){
int sum = add(2,5,6,6);
System.out.println("sum= " + sum);
int sum1 = add(2,5,6);
System.out.println("sum1= " + sum1);
}
public static int add(int... arr){ //int... 和int[]等效,簡化書寫。調用傳參的時候不需要建立數組,直接傳值。
int sum = 0;
for(int i:arr)
sum+=i;
return sum;
}
5.枚舉類:
1.作用:一些程序在運行時,它需要的數據不能是任意的,而必須是一定範圍內的值,jdk5以前用自定義類來解決,jdk5以後可以直接採用枚舉類解決。
2.用enum關鍵字定義一個枚舉類。
3.一個枚舉也可以用構造函數,字段,和方法。
4.示例:
public class Demo1 {
public void test(){
print(Grade.B);
}
public void print(Grade g){ //A B C D E
}
}
/*class Grade{
private Grade(){}
public static final Grade A =new Grade();
public static final Grade B =new Grade();
public static final Grade C =new Grade();
public static final Grade D =new Grade();
public static final Grade E =new Grade();
}*/
//等效於
enum Grade{ //class
A,B,C,D,E; //Object
}
5.定義枚舉的構造方法,方法,和字段:
public class Demo1 {
@Test
public void test(){
print(Grade.B);
}
public void print(Grade g){ //A B C D E
String value = g.getValue();
System.out.println(value);
}
}
/*class Grade{
private Grade(){}
public static final Grade A =new Grade();
public static final Grade B =new Grade();
public static final Grade C =new Grade();
}*/
//等效於
//如何定義枚舉的構造方法,方法,和字段去封裝更對的信息
enum Grade{ //class A 100-90 B 89-80 C 79-70
A("100-90"),B("89-80"),C("79-70"); //Object
private String value; //封裝每個對象對應的分數
private Grade(String value){
this.value = value;
}
public String getValue(){
return this.value;
}
}
6.帶抽象方法的枚舉:
public class Demo1 {
@Test
public void test(){
print(Grade.B);
}
public void print(Grade g){ //A B C D E
String value = g.getValue();
String lValue = g.localeValue();
System.out.println(value + "("+lValue+")");
}
}
//帶抽象方法的枚舉
enum Grade{ //class A 100-90 優 B 89-80良 C 79-70一般
A("100-90"){
public String localeValue(){
return "優";
}
}
,B("89-80"){
public String localeValue(){
return "良";
}
}
,C("79-70"){ //Object
public String localeValue(){
return "一般";
}
};
private String value; //封裝每個對象對應的分數
private Grade(String value){
this.value = value;
}
public String getValue(){
return this.value;
}
public abstract String localeValue();
}
7.枚舉的常用方法和其他細節:
①枚舉類也是一種特殊形式的Java類
②枚舉類中聲明的每一個枚舉值代表枚舉類的一個示例對象。
③與java中的普通類一樣,在聲明枚舉類時,也可以聲明屬性,方法和構造函數,但枚舉類的構造函數必須爲私有的。
④枚舉類也可以實現接口,或繼承抽象類。
⑤JDK5中還擴展了switch語句,它除了可以接收int,byte,cher,short外,還可以接收一個枚舉類型。
⑥若枚舉類只有一個枚舉值,則可以當作單態設計模式使用。
Java中聲明的枚舉類,均是java.lang.Enum類的孩子,它繼承了Enum類的所有方法。常用方法:
name()返回此枚舉常量的名稱,在其枚舉聲明中對其進行聲明。
ordinal()返回枚舉常量的序數(它在枚舉聲明中的位置,其中初始常量序數爲零)。 大多數程序員不會使用此方法。它被設計用於複雜的基於枚舉的數據結構,比如 EnumSet 和 EnumMap。
valueOf(Class enumClass, String name) 返回帶指定名稱的指定枚舉類型的枚舉常量。如果不存在字符串對應的枚舉,就會報錯。用於判斷用戶提交的字符串是否是枚舉。
values()此方法雖然在在JDK文檔中查找不到,但每個枚舉類都具有該方法,它用於遍歷枚舉的所有枚舉值。
//測試枚舉的常用方法
@Test
public void test2(){
System.out.println(Grade.A.name());
System.out.println(Grade.A.ordinal());
String str = "B";
// Grade g = Grade.valueOf(Grade.class,str);
Grade g = Grade.valueOf(str);
System.out.println(g);
Grade gs[] = Grade.values();
for(Grade gg : gs){
System.out.print(gg);
}
}
6.反射技術:
1.一個類有多個組成部分,例如:成員變量,方法,構造方法等。反射就是加載類,並解剖出類的各個組成部分。
2.什麼情況下需要加載類,並解剖出類的各個組成部分:
加載類:
1.java中有一個Class類用於代表某一個類的字節碼。
2.Class類既然代表某個類的字節碼,它當然就是要提供加載某個類字節碼的方法:forName()。
forName方法用於加載某個類的字節碼到內存中,並使用class對象進行封裝。
static Class<?> forName(String name, boolean initialize, ClassLoader loader)
使用給定的類加載器,返回與帶有給定字符串名的類或接口相關聯的 Class 對象。
3.另外兩種得到class對象的方式:
類名.class
對象.getClass()
public class Demo2 {
/*
反射:加載類,獲得類是字節碼
*/
public static void main(String[] args) throws ClassNotFoundException {
//1.
Class clazz = Class.forName("/myday01/src/cn/itcast/eclipse/Person");
//2.
Class clazz1 = new Person().getClass();
//3.
Class clazz2 = Person.class;
}
}
解剖類:
1.Class對象提供瞭如下常用方法:
①返回public的成員
Constructor<T> getConstructor(Class<?>... parameterTypes)
返回一個 Constructor 對象,它反映此 Class 對象所表示的類的指定公共構造方法。
Method getMethod(String name, Class<?>... parameterTypes)
返回一個 Method 對象,它反映此 Class 對象所表示的類或接口的指定公共成員方法。
Field getField(String name)
返回一個 Field 對象,它反映此 Class 對象所表示的類或接口的指定公共成員字段。
②返回類聲明的所有成員
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
返回一個 Constructor 對象,該對象反映此 Class 對象所表示的類或接口的指定構造方法。
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一個 Method 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明方法。
Field getDeclaredField(String name)
返回一個 Field 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明字段。
2.這些方法分別用於從類中解剖出構造函數,方法和成員變量。解剖出的成員分別用Constructor,Method,Field對象表示。
3.如果你是一個框架的設計者,解剖出這些成員後你會幹什麼:
使用。
反射類的構造函數:
利用Constructor創建對象
1.Constructor類提供瞭如下方法,用於創建類的對象。
T newInstance(Object... initargs)
使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,並用指定的初始化參數初始化該實例。
initargs用於指定構造函數接收的參數。
2.練習:反射類無參,有參,私有的構造函數,創建類的對象。
另:
class對象中也有一個newInstance()方法,用於創建類的對象。這樣開發人員可以避免每次都需要反射Constructor類以創建對象。
但是需要注意的是:class.newInstance()方法內部是反射類無參的構造函數創建的對象,所以用此種方式創建類對象時,類必須有一個無參的構造函數。
示例:
//反射類的構造函數,創建類的對象
public class Demo2 {
//反射構造函數:public Person()
@Test
public void test1() throws Exception{
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Constructor c = clazz.getConstructor(null);
Person p = (Person) c.newInstance(null);
System.out.println(p.name);
}
//反射構造函數:public Person(String name)
@Test
public void test2() throws Exception{
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Constructor c = clazz.getConstructor(String.class);
Person p = (Person) c.newInstance("小米");
System.out.println(p.name);
}
//反射構造函數:public Person(String name,int password)
@Test
public void test3() throws Exception{
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Constructor c = clazz.getConstructor(String.class,int.class);
Person p = (Person) c.newInstance("小米",4000);
System.out.println(p.name);
}
//反射構造函數:private Person(List list)
@Test
public void test4() throws Exception{
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Constructor c = clazz.getDeclaredConstructor(ArrayList.class);
c.setAccessible(true); //暴力反射
Person p = (Person) c.newInstance(new ArrayList());
System.out.println(p.name);
}
//創建(通過無參構造函數)對象的另外一種途徑
@Test
public void test5() throws Exception{
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Person p = (Person)clazz.newInstance();
System.out.println(p.name);
}
}
public class Person {
public String name = "xiaoming";
public Person(){
System.out.println("person");
}
public Person(String name){
System.out.println(name);
}
public Person(String name,int password){
System.out.println(name+":"+password);
}
private Person(ArrayList list){
System.out.println("list");
}
}
私有的東西只能被內部訪問,但是反射類可以實現。
反射類的方法:
利用Method執行方法
1.Method對象提供瞭如下方法,用於執行它所代表的方法:
Object invoke(Object obj, Object... args)
對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法。
2.練習:使用Method分別執行無參,有參,多參(帶數組和基本數據類型),靜態,私有的方法。
另:
jdk1.4和jdk1.5的invoke方法的區別:
jdk1.5:Object invoke(Object obj,Object...args)
jdk1.4:Object invoke(Object obj,Object[] args)
示例:
//反射類的方法
public class Demo2 {
//反射類的方法:public void aa1()
@Test
public void test1() throws Exception{
Person p =new Person();
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Method method = clazz.getMethod("aa1", null);
method.invoke(p, null);
}
//反射類的方法:public void aa1(String name,int password)
@Test
public void test2() throws Exception{
Person p =new Person();
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Method method = clazz.getMethod("aa1", String.class,int.class);
method.invoke(p, "xiaoming",20);
}
//反射類的方法:public Class[] aa1(String name,int[] passwprd)
@Test
public void test3() throws Exception{
Person p =new Person();
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Method method = clazz.getMethod("aa1", String.class,int[].class);
method.invoke(p, "laowang",new int[]{1,23});
}
//反射類的方法:private void aa1(InputStream in)
@Test
public void test4() throws Exception{
Person p =new Person();
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Method method = clazz.getDeclaredMethod("aa1", InputStream.class);
method.setAccessible(true);
method.invoke(p, new FileInputStream("D:\\practice1.txt"));
}
//反射類的方法:public static void aa1(int num)
@Test
public void test5() throws Exception{
// Person p =new Person(); //靜態方法調用時可以不需要對象
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Method method = clazz.getMethod("aa1", int.class);
method.invoke(null, 23);
}
}
public class Person {
public String name = "xiaoming";
public Person(){
System.out.println("person");
}
public void aa1(){
System.out.println("aa1");
}
public void aa1(String name,int password){
System.out.println(name+":"+password);
}
public Class[] aa1(String name,int[] passwprd){
return new Class[]{String.class};
}
private void aa1(InputStream in){
System.out.println(in);
}
public static void aa1(int num){
System.out.println(num);
}
public static void main(String[] args) {
System.out.println("main!");
}
}
反射類的main方法:
//反射類的方法:public static void main(String[] args)
@Test
public void test6() throws Exception{
// Person p =new Person();
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Method method = clazz.getMethod("main", String[].class);
// method.invoke(null, new Object[]{new String[]{"aa","bb"}}); //方式一
method.invoke(null, (Object)new String[]{"aa","bb"}); //方式二
//jdk1.5爲了兼容jdk1.4,在傳入的參數是一個數組時,會把數組的元素拆成多個參數進行傳遞。
}
反射類的字段
//反射字段
public class Demo2 {
//反射字段: public String name = "xiaoming";
@Test
public void test1() throws Exception{
Person p = new Person();
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Field f = clazz.getField("name");
//獲取字段的值
Object value = f.get(p);
//獲取字段的類型
Class type = f.getType();
if(type.equals(String.class)){
String svalue = (String)value;
System.out.println(svalue);
}
//設置字段的值
f.set(p, "xxxx");
}
//反射字段: private int password;
@Test
public void test2() throws Exception{
Person p = new Person();
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Field f = clazz.getDeclaredField("password");
f.setAccessible(true);
System.out.println(f.get(p));
}
//反射字段: private static int age; 和訪問私有成員變量一樣
@Test
public void test3() throws Exception{
Person p = new Person();
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Field f = clazz.getDeclaredField("age");
f.setAccessible(true);
System.out.println(f.get(p));
}
}
public class Person {
public String name = "xiaoming";
private int password = 12;
private static int age = 32;
public Person(){
System.out.println("person");
}
7.內省操作:introspector類
1.開發框架時,經常需要使用java對象的屬性來封裝程序的數據,每次都使用反射技術完成此類操作過於麻煩,所以sun公司開發了一套API,專門用於操作java對象(javabean)的屬性。
2.什麼是Java對象的屬性和屬性的讀寫方法:
public class Person { //javabean,這個bean有4個屬性(包括getClass()屬性)。
private String name; //字段
private String password;
private int age;
public String getName() { //屬性
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
3.內省訪問javabean屬性的兩種方法:
①通過Introspector類獲得Bean對象的BeanInfo,然後通過BeanInfo來獲得屬性的描述器(PropertyDescriptor),通過這個屬性描述器就可以獲取某個屬性對應的getter/setter方法,然後通過反射機制來調用這些方法。
②通過 PropertyDescriptor類操作Bean的屬性。
//使用內省api操作bean的屬性
public class Demo2 {
//得到bean的所有屬性
@Test
public void test1() throws Exception{
BeanInfo info = Introspector.getBeanInfo(Person.class,Object.class); //不要class屬性
PropertyDescriptor[] pds = info.getPropertyDescriptors();
for(PropertyDescriptor pd:pds){
System.out.println(pd.getName());
}
}
//操作bean的指定屬性:age
@Test
public void test2() throws Exception{
Person p = new Person();
PropertyDescriptor pd = new PropertyDescriptor("age", Person.class);
//得到屬性的寫方法,爲屬性賦值
Method method = pd.getWriteMethod(); //setAge
method.invoke(p, 45);
//獲得屬性的值
method = pd.getReadMethod();
System.out.println(method.invoke(p, null));
}
//獲取當前操作的屬性的類型
@Test
public void test3() throws Exception{
PropertyDescriptor pd = new PropertyDescriptor("age", Person.class);
System.out.println(pd.getPropertyType());
}
}
使用beanUtils操作javabean的屬性
//使用beanUtils操作bean的屬性
public class Demo1 {
@Test
public void test1() throws IllegalAccessException, InvocationTargetException{
Person p = new Person();
BeanUtils.setProperty(p, "name", "xcc");
System.out.println(p.getName());
}
//下面的代碼有問題的,因爲beaUtils框架只支持基本數據類型轉換。
@Test
public void test2() throws IllegalAccessException, InvocationTargetException{
String name = "xiaoming";
String password = "123";
String age = "34";
String birthday = "1980-09-09"; //需要註冊轉換器
//爲了讓日期賦到bean的birthday屬性上,我們給beanUtils註冊一個日期轉換器
ConvertUtils.register(new Converter(){
public Object convert(Class type, Object value) {
if(value==null){
return null;
}
if(!(value instanceof String)){
throw new ConversionException("只支持string類型的轉換!");
}
String str = (String)value;
if(str.trim().equals("")){
return null;
}
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
return df.parse(str);
} catch (ParseException e) {
throw new RuntimeException(e);//異常鏈不能斷
}
}
}, Date.class);
Person p = new Person();
BeanUtils.setProperty(p, "name", name);
BeanUtils.setProperty(p, "password", password);
BeanUtils.setProperty(p, "age", age); //自動將字符串轉換爲int。但是隻支持8基本數據類型
BeanUtils.setProperty(p, "birthday", birthday);
System.out.println(p.getName());
System.out.println(p.getPassword());
System.out.println(p.getAge());
System.out.println(p.getBirthday());
}
//使用beanUtils自己的轉換器,但是寫的不健壯。比如日期類“”傳入會報錯
@Test
public void test3() throws IllegalAccessException, InvocationTargetException{
String name = "xiaoming";
String password = "123";
String age = "34";
String birthday = "1980-09-09"; //需要註冊轉換器
//爲了讓日期賦到bean的birthday屬性上,我們給beanUtils註冊一個日期轉換器
ConvertUtils.register(new DateLocaleConverter(), Date.class);
Person p = new Person();
BeanUtils.setProperty(p, "name", name);
BeanUtils.setProperty(p, "password", password);
BeanUtils.setProperty(p, "age", age); //自動將字符串轉換爲int。但是隻支持8基本數據類型
BeanUtils.setProperty(p, "birthday", birthday);
System.out.println(p.getName());
System.out.println(p.getPassword());
System.out.println(p.getAge());
Date date = p.getBirthday();
System.out.println(date.toLocaleString());
}
//用map集合中的值,填充bean的屬性
@Test
public void test5() throws IllegalAccessException, InvocationTargetException{
Map map = new HashMap();
map.put("name", "xiaoming");
map.put("password", "123");
map.put("age", "23");
map.put("birthday", "1980-09-09");
ConvertUtils.register(new DateLocaleConverter(), Date.class);
Person p =new Person();
BeanUtils.populate(p, map);
System.out.println(p.getName());
System.out.println(p.getPassword());
System.out.println(p.getAge());
System.out.println(p.getBirthday());
}
}