86.java基礎3面向物件中上
阿新 • • 發佈:2020-08-18
36.概念總結:
1.什麼是多型性?什麼是虛擬方法呼叫? 物件的多型性: 父類的引用執行子類的物件 Person p = new Nan(); p.ext() 呼叫方法時,編譯看左邊,執行看右邊 2.一個類可以有幾個直接父類,(只有一個)一個父類可以有多少個子類?(無數個)子類能獲取直接父類的父類的結構嗎?(可以)子類是否能獲取父類中的private許可權的屬性或方法(可以getXX/setXXX)? A is a B 3.方法的重寫(override/overwrite)的具體規則有哪些? 形參列表相同 許可權修飾符 返回值 : void -- void 基本資料型別 -- 基本資料型別 返回的異常 4.super呼叫構造器,有哪些具體的注意點 this(形參列表): 本類過載其他的構造器 super(形參列表): 呼叫父類中的執行構造器 必須寫在首行(所以和this()不能同時存在) ------------------------------------------------------------------------------------------ 1.什麼是方法的重寫(override 或 overwrite)? 子類繼承父類以後,可以對父類中同名同參數的方法,進行覆蓋操作. 2. 應用: 重寫以後,當建立子類物件以後,通過子類物件呼叫子父類中的同名同參數的方法時,實際執行的是子類重寫父類的方法。 3.舉例: class Circle{ public double findArea(){}//求面積 } class Cylinder extends Circle{ public double findArea(){}//求表面積 } *************** class Account{ public boolean withdraw(double amt){} } class CheckAccount extends Account{ public boolean withdraw(double amt){} } 4.重寫的規則: 方法的宣告: 許可權修飾符 返回值型別 方法名(形參列表) throws 異常的型別{ * //方法體 * } * 約定俗稱:子類中的叫重寫的方法,父類中的叫被重寫的方法 * ① 子類重寫的方法的方法名和形參列表與父類被重寫的方法的方法名和形參列表相同 * ② 子類重寫的方法的許可權修飾符不小於父類被重寫的方法的許可權修飾符 * >特殊情況:子類不能重寫父類中宣告為private許可權的方法 * ③ 返回值型別: * >父類被重寫的方法的返回值型別是void,則子類重寫的方法的返回值型別只能是void * >父類被重寫的方法的返回值型別是A型別,則子類重寫的方法的返回值型別可以是A類或A類的子類 * >父類被重寫的方法的返回值型別是基本資料型別(比如:double),則子類重寫的方法的返回值型別必須是相同的基本資料型別(必須也是double) * ④ 子類重寫的方法丟擲的異常型別不大於父類被重寫的方法丟擲的異常型別(具體放到異常處理時候講) * ********************************************************************** * 子類和父類中的同名同參數的方法要麼都宣告為非static的(考慮重寫,要麼都宣告為static的(不是重寫)。 5.面試題: 區分方法的重寫和過載? 答: ① 二者的概念: ② 過載和重寫的具體規則 ③ 過載:不表現為多型性。 重寫:表現為多型性。 過載,是指允許存在多個同名方法,而這些方法的引數不同。編譯器根據方法不同的引數表,對同名方法的名稱做修飾。對於編譯器而言,這些同名方法就成了不同的方法。它們的呼叫地址在編譯期就綁定了。Java的過載是可以包括父類和子類的,即子類可以過載父類的同名不同引數的方法。 所以:對於過載而言,在方法呼叫之前,編譯器就已經確定了所要呼叫的方法,這稱為“早繫結”或“靜態繫結”; 而對於多型,只等到方法呼叫的那一刻,解釋執行器才會確定所要呼叫的具體方法,這稱為“晚繫結”或“動態繫結”。 引用一句Bruce Eckel的話:“不要犯傻,如果它不是晚繫結,它就不是多型。” ------------------------------------------------------------------------------------------ 1.super 關鍵字可以理解為:父類的 2.可以用來呼叫的結構: 屬性、方法、構造器 3.super呼叫屬性、方法: 3.1 我們可以在子類的方法或構造器中。通過使用"super.屬性"或"super.方法"的方式,顯式的呼叫父類中宣告的屬性或方法。但是,通常情況下,我們習慣省略"super." 3.2 特殊情況:當子類和父類中定義了同名的屬性時,我們要想在子類中呼叫父類中宣告的屬性,則必須顯式的使用"super.屬性"的方式,表明呼叫的是父類中宣告的屬性。 3.3 特殊情況:當子類重寫了父類中的方法以後,我們想在子類的方法中呼叫父類中被重寫的方法時,則必須顯式的使用"super.方法"的方式,表明呼叫的是父類中被重寫的方法。 4.super呼叫構造器: 4.1 我們可以在子類的構造器中顯式的使用"super(形參列表)"的方式,呼叫父類中宣告的指定的構造器 4.2 "super(形參列表)"的使用,必須宣告在子類構造器的首行! 4.3 我們在類的構造器中,針對於"this(形參列表)"或"super(形參列表)"只能二一,不能同時出現 4.4 在構造器的首行,沒顯式的宣告"this(形參列表)"或"super(形參列表)",則預設呼叫的是父類中空參的構造器:super() 4.5 在類的多個構造器中,至少一個類的構造器中使用了"super(形參列表)",呼叫父類中的構造器 ------------------------------------------------------------------------------------------ 理解即可。 1.從結果上看:繼承性 > 子類繼承父類以後,就獲取了父類中宣告的屬性或方法。 > 建立子類的物件,在堆空間中,就會載入所父類中宣告的屬性。 2.從過程上看: 當我們通過子類的構造器建立子類物件時,我們一定會直接或間接的呼叫其父類的構造器,進而呼叫父類的父類的構造器,...直到呼叫了java.lang.Object類中空參的構造器為止。正因為載入過所的父類的結構,所以才可以看到記憶體中父類中的結構,子類物件才可以考慮進行呼叫。 3.強調說明: 雖然建立子類物件時,呼叫了父類的構造器,但是自始至終就建立過一個物件,即為new的子類物件。
37.多型性總結:
1.多型性的理解:可以理解為一個事物的多種形態。 2.何為多型性: 物件的多型性:父類的引用指向子類的物件(或子類的物件賦給父類的引用) 舉例: Person p = new Man(); Object obj = new Date(); 3.多型性的使用:虛擬方法呼叫 > 有了物件的多型性以後,我們在編譯期,只能呼叫父類中宣告的方法,但在執行期,我們實際執行的是子類重寫父類的方法。 > 總結:編譯,看左邊;執行,看右邊。 4.多型性的使用前提: ① 類的繼承關係 ② 方法的重寫 5.多型性的應用舉例: 舉例一: public void func(Animal animal){//Animal animal = new Dog(); animal.eat(); animal.shout(); } 舉例二: public void method(Object obj){ } 舉例三: class Driver{ public void doData(Connection conn){//conn = new MySQlConnection(); / conn = new OracleConnection(); //規範的步驟去操作資料 // conn.method1(); // conn.method2(); // conn.method3(); } } 6.多型性使用的注意點: 物件的多型性,只適用於方法,不適用於屬性(編譯和執行都看左邊) ************************************************************ 7.關於向上轉型與向下轉型: 7.1 向上轉型:多型 7.2 向下轉型: 7.2.1 為什麼使用向下轉型: 有了物件的多型性以後,記憶體中實際上是載入了子類特有的屬性和方法的,但是由於變數宣告為父類型別,導致編譯時,只能呼叫父類中宣告的屬性和方法。子類特有的屬性和方法不能呼叫。如何才能呼叫子類特的屬性和方法?使用向下轉型。 7.2.2 如何實現向下轉型: 使用強制型別轉換符:() 7.2.3 使用時的注意點: ① 使用強轉時,可能出現ClassCastException的異常。 ② 為了避免在向下轉型時出現ClassCastException的異常,我們在向下轉型之前,先進行instanceof的判斷,一旦返回true,就進行向下轉型。如果返回false,不進行向下轉型。 7.2.4 instanceof的使用: ① a instanceof A:判斷物件a是否是類A的例項。如果是,返回true;如果不是,返回false。 ② 如果 a instanceof A返回true,則 a instanceof B也返回true.其中,類B是類A的父類。 ③ 要求a所屬的類與類A必須是子類和父類的關係,否則編譯錯誤。 7.2.5 圖示: 8. 面試題: 8.1 談談你對多型性的理解? ① 實現程式碼的通用性。 ② Object類中定義的public boolean equals(Object obj){ } JDBC:使用java程式操作(獲取資料庫連線、CRUD)資料庫(MySQL、Oracle、DB2、SQL Server) ③ 抽象類、介面的使用肯定體現了多型性。(抽象類、介面不能例項化) 8.2 多型是編譯時行為還是執行時行為? 執行時的行為
38.java向下轉型:
package com.atguigu.java; import java.util.Date; /* * 面向物件特徵之三:多型性 * * 1.理解多型性:可以理解為一個事物的多種形態。 * 2.何為多型性: * 物件的多型性:父類的引用指向子類的物件(或子類的物件賦給父類的引用) * * 3. 多型的使用:虛擬方法呼叫 * 有了物件的多型性以後,我們在編譯期,只能呼叫父類中宣告的方法,但在執行期,我們實際執行的是子類重寫父類的方法。 * 總結:編譯,看左邊;執行,看右邊。 * * 4.多型性的使用前提: ① 類的繼承關係 ② 方法的重寫 * * 5.物件的多型性,只適用於方法,不適用於屬性(編譯和執行都看左邊) * * ************************************************************* * * */ public class PersonTest { public static void main(String[] args) { Person p1 = new Person(); p1.eat(); Man man = new Man(); man.eat(); man.age = 25; man.earnMoney(); //************************************************* System.out.println("*******************"); //物件的多型性:父類的引用指向子類的物件 Person p2 = new Man(); // Person p3 = new Woman(); //多型的使用:當呼叫子父類同名同參數的方法時,實際執行的是子類重寫父類的方法 ---虛擬方法呼叫 p2.eat(); p2.walk(); // p2.earnMoney(); System.out.println(p2.id);//1001 System.out.println("****************************"); //不能呼叫子類所特有的方法、屬性:編譯時,p2是Person型別。 p2.name = "Tom"; // p2.earnMoney(); // p2.isSmoking = true; //有了物件的多型性以後,記憶體中實際上是載入了子類特有的屬性和方法的,但是由於變數宣告為父類型別,導致 //編譯時,只能呼叫父類中宣告的屬性和方法。子類特有的屬性和方法不能呼叫。 //如何才能呼叫子類特有的屬性和方法? //向下轉型:使用強制型別轉換符。 Man m1 = (Man)p2; m1.earnMoney(); m1.isSmoking = true; //使用強轉時,可能出現ClassCastException的異常。 // Woman w1 = (Woman)p2; //型別不配的時候會報錯 // w1.goShopping(); /* * instanceof關鍵字的使用 * * a instanceof A:判斷物件a是否是類A的例項。如果是,返回true;如果不是,返回false。 * * * 使用情境:為了避免在向下轉型時出現ClassCastException的異常,我們在向下轉型之前,先 * 進行instanceof的判斷,一旦返回true,就進行向下轉型。如果返回false,不進行向下轉型。 * * 如果 a instanceof A返回true,則 a instanceof B也返回true. * 其中,類B是類A的父類。 */ if(p2 instanceof Woman){ Woman w1 = (Woman)p2; w1.goShopping(); System.out.println("******Woman******"); } if(p2 instanceof Man){ Man m2 = (Man)p2; m2.earnMoney(); System.out.println("******Man******"); } if(p2 instanceof Person){ System.out.println("******Person******"); } if(p2 instanceof Object){ System.out.println("******Object******"); } // if(p2 instanceof String){ // // } //練習: //問題一:編譯時通過,執行時不通過 //舉例一: // Person p3 = new Woman(); // Man m3 = (Man)p3; //舉例二: // Person p4 = new Person(); // Man m4 = (Man)p4; //問題二:編譯通過,執行時也通過 // Object obj = new Woman(); // Person p = (Person)obj; //Women不是Person的父類 //問題三:編譯不通過 // Man m5 = new Woman(); // String str = new Date(); // Object o = new Date(); // String str1 = (String)o; } } //class Order{ // //} ------------------------------------------------------ package com.atguigu.exer; /* * 練習: * 1.若子類重寫了父類方法,就意味著子類裡定義的方法徹底覆蓋了父類裡的同名方法, * 系統將不可能把父類裡的方法轉移到子類中:編譯看左邊,執行看右邊 * * 2.對於例項變數則不存在這樣的現象,即使子類裡定義了與父類完全相同的例項變數, * 這個例項變數依然不可能覆蓋父類中定義的例項變數:編譯執行都看左邊 */ class Base { int count = 10; public void display() { System.out.println(this.count); } } class Sub extends Base { int count = 20; public void display() { System.out.println(this.count); } } public class FieldMethodTest { public static void main(String[] args) { Sub s = new Sub(); System.out.println(s.count);//20 s.display();//20 Base b = s;//多型性 //==:對於引用資料型別來講,比較的是兩個引用資料型別變數的地址值是否相同 System.out.println(b == s);//true System.out.println(b.count);//10 b.display();//20 } }
38.多型練習1:
package com.atguigu.exer;
/*
* 建立InstanceTest 類,在類中定義方法method(Person e);
在method中:
(1)根據e的型別呼叫相應類的getInfo()方法。
(2)根據e的型別執行:
如果e為Person類的物件,輸出:
“a person”;
如果e為Student類的物件,輸出:
“a student”
“a person ”
如果e為Graduate類的物件,輸出:
“a graduated student”
“a student”
“a person”
*/
public class InstanceTest {
public static void main(String[] args) {
InstanceTest test = new InstanceTest();
test.method(new Student());
}
public void method(Person e){
//虛擬方法呼叫
String info = e.getInfo();
System.out.println(info);
//方式一
// if(e instanceof Graduate){
// System.out.println("a graduated student");
// System.out.println("a student");
// System.out.println("a person");
// }else if(e instanceof Student){
// System.out.println("a student");
// System.out.println("a person");
// }else{
// System.out.println("a person");
// }
//方式二
if(e instanceof Graduate){
System.out.println("a graduated student");
}
if(e instanceof Student){
System.out.println("a student");
}
if(e instanceof Person){
System.out.println("a person");
}
}
}
class Person {
protected String name = "person";
protected int age = 50;
public String getInfo() {
return "Name: " + name + "\n" + "age: " + age;
}
}
class Student extends Person {
protected String school = "pku";
public String getInfo() {
return "Name: " + name + "\nage: " + age + "\nschool: " + school;
}
}
class Graduate extends Student {
public String major = "IT";
public String getInfo() {
return "Name: " + name + "\nage: " + age + "\nschool: " + school + "\nmajor:" + major;
}
}
40.equales和==
package com.atguigu.java1;
import java.util.Date;
/*
* 面試題: == 和 equals() 區別
*
* 一、回顧 == 的使用:
* == :運算子
* 1. 可以使用在基本資料型別變數和引用資料型別變數中
* 2. 如果比較的是基本資料型別變數:比較兩個變數儲存的資料是否相等。(不一定型別要相同)
* 如果比較的是引用資料型別變數:比較兩個物件的地址值是否相同.即兩個引用是否指向同一個物件實體
* 補充: == 符號使用時,必須保證符號左右兩邊的變數型別一致。否則編譯不通過
*
* 二、equals()方法的使用:
* 1. 是一個方法,而非運算子
* 2. 只能適用於引用資料型別
* 3. Object類中equals()的定義:
* public boolean equals(Object obj) {
return (this == obj);
}
* 說明:Object類中定義的equals()和==的作用是相同的:比較兩個物件的地址值是否相同.即兩個引用是否指向同一個物件實體
*
* 4. 像String、Date、File、包裝類等都重寫了Object類中的equals()方法。重寫以後,比較的不是
* 兩個引用的地址是否相同,而是比較兩個物件的"實體內容"是否相同。
*
* 5. 通常情況下,我們自定義的類如果使用equals()的話,也通常是比較兩個物件的"實體內容"是否相同。那麼,我們
* 就需要對Object類中的equals()進行重寫.
* 重寫的原則:比較兩個物件的實體內容是否相同.
*/
public class EqualsTest {
public static void main(String[] args) {
//基本資料型別
int i = 10;
int j = 10;
double d = 10.0;
System.out.println(i == j);//true
System.out.println(i == d);//true
boolean b = true;
// System.out.println(i == b);
char c = 10;
System.out.println(i == c);//true
char c1 = 'A';
char c2 = 65;
System.out.println(c1 == c2);//true
//引用型別:
Customer cust1 = new Customer("Tom",21);
Customer cust2 = new Customer("Tom",21);
System.out.println(cust1 == cust2);//false
String str1 = new String("atguigu");
String str2 = new String("atguigu");
System.out.println(str1 == str2);//false
System.out.println("****************************");
System.out.println(cust1.equals(cust2));//false--->true
System.out.println(str1.equals(str2));//true
Date date1 = new Date(32432525324L);
Date date2 = new Date(32432525324L);
System.out.println(date1.equals(date2));//true
}
}
-------------------------------------------重寫equales-------------------------------------------
package com.atguigu.java1;
public class Customer {
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;
}
public Customer() {
super();
}
public Customer(String name, int age) {
super();
this.name = name;
this.age = age;
}
//自動生成的equals()
// @Override
// public boolean equals(Object obj) {
// if (this == obj)
// return true;
// if (obj == null)
// return false;
// if (getClass() != obj.getClass())
// return false;
// Customer other = (Customer) obj;
// if (age != other.age)
// return false;
// if (name == null) {
// if (other.name != null)
// return false;
// } else if (!name.equals(other.name))
// return false;
// return true;
// }
//重寫的原則:比較兩個物件的實體內容(即:name和age)是否相同
//手動實現equals()的重寫
// @Override
// public boolean equals(Object obj) {
//
//// System.out.println("Customer equals()....");
// if (this == obj) {
// return true;
// }
//
// if(obj instanceof Customer){
// Customer cust = (Customer)obj;
// //比較兩個物件的每個屬性是否都相同
//// if(this.age == cust.age && this.name.equals(cust.name)){
//// return true;
//// }else{
//// return false;
//// }
// //或
// return this.age == cust.age && this.name.equals(cust.name);
// }else{
// return false;
// }
//
// }
}
---------------------------------------練習題---------------------------------------
package com.atguigu.exer2;
/*
* 編寫Order類,有int型的orderId,String型的orderName,
* 相應的getter()和setter()方法,兩個引數的構造器,
* 重寫父類的equals()方法:public boolean equals(Object obj),
* 並判斷測試類中建立的兩個物件是否相等。
*/
public class OrderTest {
public static void main(String[] args) {
Order order1 = new Order(1001, "AA");
Order order2 = new Order(1001, "BB"); //true
Order order2 = new Order(1001, new String("BB"));
System.out.println(order1.equals(order2));
Order order3 = new Order(1001, "BB");
System.out.println(order2.equals(order3));
// String s1 = "BB";
// String s2 = "BB";
// System.out.println(s1 == s2);//true
}
}
class Order{
private int orderId;
private String orderName;
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public Order(int orderId, String orderName) {
super();
this.orderId = orderId;
this.orderName = orderName;
}
@Override
public boolean equals(Object obj) {
if(this == obj){
return true;
}
if(obj instanceof Order){
Order order = (Order)obj;
//正確的:
return this.orderId == order.orderId &&
this.orderName.equals(order.orderName); //這裡必須使用equales
//錯誤的:
// return this.orderId == order.orderId &&
// this.orderName == order.orderName;
}
return false;
}
}
41.toString方法
package com.atguigu.java1;
import java.util.Date;
/*
* Object類中toString()的使用:
* 1. 當我們輸出一個物件的引用時,實際上就是呼叫當前物件的toString()
* 2. Object類中toString()的定義:
* public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
* 3. 像String、Date、File、包裝類等都重寫了Object類中的toString()方法。
* 使得在呼叫物件的toString()時,返回"實體內容"資訊
* 4. 自定義類也可以重寫toString()方法,當呼叫此方法時,返回物件的"實體內容"
*/
public class ToStringTest {
public static void main(String[] args) {
Customer cust1 = new Customer("Tom",21);
System.out.println(cust1.toString());//com.atguigu.java1.Customer@15db9742-->Customer[name = Tom,age = 21]
System.out.println(cust1);//com.atguigu.java1.Customer@15db9742-->Customer[name = Tom,age = 21]
String str = new String("MM");
System.out.println(str);//MM
Date date = new Date(4534534534543L);
System.out.println(date.toString());//Mon Sep 11 08:55:34 GMT+08:00 2113
}
}
-----------------------------------------重寫toString--------------------------------------------
//手動實現
// @Override
// public String toString() {
// return "Customer[name = " + name + ",age = " + age + "]";
// }
//自動實現
@Override
public String toString() {
return "Customer [name=" + name + ", age=" + age + "]";
}
-------------------------------------------------------------------------------------------
package com.atguigu.exer3;
/*
* 寫一個測試類,建立兩個Circle物件,判斷其顏色是否相等;
* 利用equals方法判斷其半徑是否相等;利用toString()方法輸出其半徑。
*/
public class CircleTest {
public static void main(String[] args) {
Circle circle1 = new Circle(2.3);
Circle circle2 = new Circle(3.3, new String("white"), 2.0);
System.out.println("顏色是否相等:" + circle1.getColor().equals(circle2.getColor()));
System.out.println("半徑是否相等:" + circle1.equals(circle2));
System.out.println(circle1);
System.out.println(circle2.toString());
}
}
42.java單元測試:
package com.atguigu.java2;
import java.util.Date;
import org.junit.Test;
/*
* Java中的JUnit單元測試
* 步驟:
* 1.選中當前工程 - 右鍵選擇:build path - add libraries - JUnit 4 - 下一步
* 2.建立Java類,進行單元測試。
* 此時的Java類要求:① 此類是public的 ②此類提供公共的無參的構造器(不需要寫構造器或者構造器不能有引數)
* 3.此類中宣告單元測試方法。
* 此時的單元測試方法:方法的許可權是public,沒有返回值,沒有形參
* 4.此單元測試方法上需要宣告註解:@Test,並在單元測試類中匯入:import org.junit.Test;
* 5.宣告好單元測試方法以後,就可以在方法體內測試相關的程式碼。
* 6.寫完程式碼以後,左鍵雙擊單元測試方法名,右鍵:run as - JUnit Test
* 說明:
* 1.如果執行結果沒有任何異常:綠條
* 2.如果執行結果出現異常:紅條
*/
public class JUnitTest {
int num = 10;
@Test
public void testEquals(){
String s1 = "MM";
String s2 = "MM";
System.out.println(s1.equals(s2));
//ClassCastException的異常
// Object obj = new String("GG");
// Date date = (Date)obj;
System.out.println(num);
show();
}
public void show(){
num = 20;
System.out.println("show()....");
}
@Test
public void testToString(){
String s2 = "MM";
System.out.println(s2.toString());
}
}
43.java包裝類:
package com.atguigu.java2;
import org.junit.Test;
/*
* 包裝類的使用:
* 1.java提供了8種基本資料型別對應的包裝類,使得基本資料型別的變數具有類的特徵
* 2.掌握的:基本資料型別、包裝類、String三者之間的相互轉換
*/
public class WrapperTest {
//String型別 --->基本資料型別、包裝類:呼叫包裝類的parseXxx(String s)
@Test
public void test5(){
String str1 = "123";
//錯誤的情況:
// int num1 = (int)str1;
// Integer in1 = (Integer)str1;
//可能會報NumberFormatException
int num2 = Integer.parseInt(str1);
System.out.println(num2 + 1);
String str2 = "true1";
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1);
}
//基本資料型別、包裝類--->String型別:呼叫String過載的valueOf(Xxx xxx)
@Test
public void test4(){
int num1 = 10;
//方式1:連線運算
String str1 = num1 + "";
//方式2:呼叫String的valueOf(Xxx xxx)
float f1 = 12.3f;
String str2 = String.valueOf(f1);//"12.3"
Double d1 = new Double(12.4);
String str3 = String.valueOf(d1);
System.out.println(str2);
System.out.println(str3);//"12.4"
}
/*
* JDK 5.0 新特性:自動裝箱 與自動拆箱
*/
@Test
public void test3(){
int num1 = 10;
// //基本資料型別-->包裝類的物件
method(num1);
//自動裝箱:基本資料型別 --->包裝類
int num2 = 10;
Integer in1 = num2;//自動裝箱
boolean b1 = true;
Boolean b2 = b1;//自動裝箱
//自動拆箱:包裝類--->基本資料型別
System.out.println(in1.toString());
int num3 = in1;//自動拆箱
}
public void method(Object obj){
System.out.println(obj.toString());
}
//包裝類--->基本資料型別:呼叫包裝類Xxx的xxxValue()
@Test
public void test2(){
Integer in1 = new Integer(12);
int i1 = in1.intValue();
System.out.println(i1 + 1);
Float f1 = new Float(12.3);
float f2 = f1.floatValue();
System.out.println(f2 + 1);
}
//基本資料型別 --->包裝類:呼叫包裝類的構造器
@Test
public void test1(){
int num1 = 10;
// System.out.println(num1.toString());
Integer in1 = new Integer(num1);
System.out.println(in1.toString());
Integer in2 = new Integer("123");
System.out.println(in2.toString());
//報異常
// Integer in3 = new Integer("123abc");
// System.out.println(in3.toString());
Float f1 = new Float(12.3f);
Float f2 = new Float("12.3");
System.out.println(f1);
System.out.println(f2);
Boolean b1 = new Boolean(true);
Boolean b2 = new Boolean("TrUe");
System.out.println(b2);
Boolean b3 = new Boolean("true123");
System.out.println(b3);//false
Order order = new Order();
System.out.println(order.isMale);//false
System.out.println(order.isFemale);//null 它已經是一個引用資料型別
}
}
class Order{
boolean isMale;
Boolean isFemale;
}
-------------------------------------------面試題1------------------------------------
package com.atguigu.java2;
import org.junit.Test;
/*
* 關於包裝類使用的面試題
*/
public class InterviewTest {
@Test
public void test1() {
//編譯時候後面兩隻型別自動提升
Object o1 = true ? new Integer(1) : new Double(2.0);
System.out.println(o1);// 1.0
}
@Test
public void test2() {
Object o2;
if (true)
o2 = new Integer(1);
else
o2 = new Double(2.0);
System.out.println(o2);// 1
}
@Test
public void test3() {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);//false
//Integer內部定義了IntegerCache結構,IntegerCache中定義了Integer[],
//儲存了從-128~127範圍的整數。如果我們使用自動裝箱的方式,給Integer賦值的範圍在
//-128~127範圍內時,可以直接使用陣列中的元素,不用再去new了。目的:提高效率
Integer m = 1;
Integer n = 1;
System.out.println(m == n);//true
Integer x = 128;//相當於new了一個Integer物件
Integer y = 128;//相當於new了一個Integer物件
System.out.println(x == y);//false
}
}
---------------------------------------------面試題2-------------------------------------
package com.atguigu.exer4;
import java.util.Scanner;
import java.util.Vector;
import org.omg.CORBA.VersionSpecHelper;
/*
* 利用Vector代替陣列處理:從鍵盤讀入學生成績(以負數代表輸入結束),找出最高分,並輸出學生成績等級。
提示:陣列一旦建立,長度就固定不變,所以在建立陣列前就需要知道它的長度。
而向量類java.util.Vector可以根據需要動態伸縮。
建立Vector物件:Vector v=new Vector();
給向量新增元素:v.addElement(Object obj); //obj必須是物件
取出向量中的元素:Object obj=v.elementAt(0);
注意第一個元素的下標是0,返回值是Object型別的。
計算向量的長度:v.size();
若與最高分相差10分內:A等;20分內:B等;
30分內:C等;其它:D等
*/
public class ScoreTest {
public static void main(String[] args) {
//1.例項化Scanner,用於從鍵盤獲取學生成績
Scanner scan = new Scanner(System.in);
//2.建立Vector物件:Vector v=new Vector();相當於原來的陣列
Vector v = new Vector();
//3.通過for(;;)或while(true)方式,給Vector中新增陣列
int maxScore = 0;
for(;;){
System.out.println("請輸入學生成績(以負數代表輸入結束)");
int score = scan.nextInt();
//3.2 當輸入是負數時,跳出迴圈
if(score < 0){
break;
}
if(score > 100){
System.out.println("輸入的資料非法,請重新輸入");
continue;
}
//3.1 新增操作::v.addElement(Object obj)
//jdk5.0之前:
// Integer inScore = new Integer(score);
// v.addElement(inScore);//多型
//jdk5.0之後:
v.addElement(score);//自動裝箱
//4.獲取學生成績的最大值
if(maxScore < score){
maxScore = score;
}
}
//5.遍歷Vector,得到每個學生的成績,並與最大成績比較,得到每個學生的等級。
char level;
for(int i = 0;i < v.size();i++){
Object obj = v.elementAt(i);
//jdk 5.0之前:
// Integer inScore = (Integer)obj;
// int score = inScore.intValue();
//jdk 5.0之後:
int score = (int)obj;
if(maxScore - score <= 10){
level = 'A';
}else if(maxScore - score <= 20){
level = 'B';
}else if(maxScore - score <= 30){
level = 'C';
}else{
level = 'D';
}
System.out.println("student-" + i + " score is " + score + ",level is " + level);
}
}
}
44.object類說明:
1.java.lang.Object類的說明:
* 1.Object類是所Java類的根父類
* 2.如果在類的宣告中未使用extends關鍵字指明其父類,則預設父類為java.lang.Object類
* 3.Object類中的功能(屬性、方法)就具通用性。
* 屬性:無
* 方法:equals() / toString() / getClass() /hashCode() / clone() / finalize()
* wait() 、 notify()、notifyAll()
*
* 4. Object類只聲明瞭一個空參的構造器
2.equals()方法
2.1 equals()的使用:
1. 是一個方法,而非運算子
* 2. 只能適用於引用資料型別
* 3. Object類中equals()的定義:
* public boolean equals(Object obj) {
return (this == obj);
}
* 說明:Object類中定義的equals()和==的作用是相同的:比較兩個物件的地址值是否相同.即兩個引用是否指向同一個物件實體
*
* 4. 像String、Date、File、包裝類等都重寫了Object類中的equals()方法。重寫以後,比較的不是
* 兩個引用的地址是否相同,而是比較兩個物件的"實體內容"是否相同。
*
* 5. 通常情況下,我們自定義的類如果使用equals()的話,也通常是比較兩個物件的"實體內容"是否相同。那麼,我們
* 就需要對Object類中的equals()進行重寫.
* 重寫的原則:比較兩個物件的實體內容是否相同.
2.2 如何重寫equals()
2.2.1 手動重寫舉例:
class User{
String name;
int age;
//重寫其equals()方法
public boolean equals(Object obj){
if(obj == this){
return true;
}
if(obj instanceof User){
User u = (User)obj;
return this.age == u.age && this.name.equals(u.name);
}
return false;
}
}
2.2.2 開發中如何實現:自動生成的
2.3 回顧 == 運算子的使用:
* == :運算子
* 1. 可以使用在基本資料型別變數和引用資料型別變數中
* 2. 如果比較的是基本資料型別變數:比較兩個變數儲存的資料是否相等。(不一定型別要相同)
* 如果比較的是引用資料型別變數:比較兩個物件的地址值是否相同.即兩個引用是否指向同一個物件實體
* 補充: == 符號使用時,必須保證符號左右兩邊的變數型別一致。
3. toString()方法
3.1 toString()的使用:
1. 當我們輸出一個物件的引用時,實際上就是呼叫當前物件的toString()
*
* 2. Object類中toString()的定義:
* public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
*
* 3. 像String、Date、File、包裝類等都重寫了Object類中的toString()方法。
* 使得在呼叫物件的toString()時,返回"實體內容"資訊
*
* 4. 自定義類也可以重寫toString()方法,當呼叫此方法時,返回物件的"實體內容"
3.2 如何重寫toString()
舉例:
//自動實現
@Override
public String toString() {
return "Customer [name=" + name + ", age=" + age + "]";
}
4.面試題:
① final、finally、finalize的區別?
② == 和 equals() 區別
45.單元測試方法說明:
* Java中的JUnit單元測試
*
* 步驟:
* 1.中當前工程 - 右鍵擇:build path - add libraries - JUnit 4 - 下一步
* 2.建立Java類,進行單元測試。
* 此時的Java類要求:① 此類是public的 ②此類提供公共的無參的構造器
* 3.此類中宣告單元測試方法。
* 此時的單元測試方法:方法的許可權是public,沒返回值,沒形參
*
* 4.此單元測試方法上需要宣告註解:@Test,並在單元測試類中匯入:import org.junit.Test;
*
* 5.宣告好單元測試方法以後,就可以在方法體內測試相關的程式碼。
* 6.寫完程式碼以後,左鍵雙擊單元測試方法名,右鍵:run as - JUnit Test
*
* 說明:
* 1.如果執行結果沒任何異常:綠條
* 2.如果執行結果出現異常:紅條
46.包裝類說明:
1.為什麼要有包裝類(或封裝類)
為了使基本資料型別的變數具有類的特徵,引入包裝類。
2.基本資料型別與對應的包裝類:
上圖1
3.需要掌握的型別間的轉換:(基本資料型別、包裝類、String)
上圖2
簡易版:
基本資料型別<--->包裝類:JDK 5.0 新特性:自動裝箱 與自動拆箱
基本資料型別、包裝類--->String:呼叫String過載的valueOf(Xxx xxx)
String--->基本資料型別、包裝類:呼叫包裝類的parseXxx(String s)
注意:轉換時,可能會報NumberFormatException
應用場景舉例:
① Vector類中關於新增元素,只定義了形參為Object型別的方法:
v.addElement(Object obj); //基本資料型別 --->包裝類 --->使用多型
47.static關鍵字
package com.atguigu.java1;
/*
* static關鍵字的使用
*
* 1.static:靜態的
* 2.static可以用來修飾:屬性、方法、程式碼塊、內部類
*
* 3.使用static修飾屬性:靜態變數(或類變數)
* 3.1 屬性,按是否使用static修飾,又分為:靜態屬性 vs 非靜態屬性(例項變數)
* 例項變數:我們建立了類的多個物件,每個物件都獨立的擁有一套類中的非靜態屬性。當修改其中一個物件中的
* 非靜態屬性時,不會導致其他物件中同樣的屬性值的修改。
* 靜態變數:我們建立了類的多個物件,多個物件共享同一個靜態變數。當通過某一個物件修改靜態變數時,會導致
* 其他物件呼叫此靜態變數時,是修改過了的。
* 3.2 static修飾屬性的其他說明:
* ① 靜態變數隨著類的載入而載入。可以通過"類.靜態變數"的方式進行呼叫
* ② 靜態變數的載入要早於物件的建立。
* ③ 由於類只會載入一次,則靜態變數在記憶體中也只會存在一份:存在方法區的靜態域中。
*
* ④ 類變數 例項變數
* 類 yes no
* 物件 yes yes
*
* 3.3 靜態屬性舉例:System.out; Math.PI;
*
* 4.使用static修飾方法:靜態方法
* ① 隨著類的載入而載入,可以通過"類.靜態方法"的方式進行呼叫
* ② 靜態方法 非靜態方法
* 類 yes no
* 物件 yes yes
* ③ 靜態方法中,只能呼叫靜態的方法或屬性
* 非靜態方法中,既可以呼叫非靜態的方法或屬性,也可以呼叫靜態的方法或屬性
*
* 5. static注意點:(由於靜態方法隨類載入,比例項變數和方法載入的早,所以不能再其中呼叫例項的屬性和方法)
* 5.1 在靜態的方法內,不能使用this關鍵字、super關鍵字
* 5.2 關於靜態屬性和靜態方法的使用,大家都從生命週期的角度去理解。
*
* 6. 開發中,如何確定一個屬性是否要宣告為static的?
* > 屬性是可以被多個物件所共享的,不會隨著物件的不同而不同的。
* > 類中的常量也常常宣告為static
*
* 開發中,如何確定一個方法是否要宣告為static的?
* > 操作靜態屬性的方法,通常設定為static的
* > 工具類中的方法,習慣上宣告為static的。 比如:Math、Arrays、Collections
*/
public class StaticTest {
public static void main(String[] args) {
Chinese.nation = "中國";
Chinese c1 = new Chinese();
c1.name = "姚明";
c1.age = 40;
c1.nation = "CHN";
Chinese c2 = new Chinese();
c2.name = "馬龍";
c2.age = 30;
c2.nation = "CHINA";
System.out.println(c1.nation);
//編譯不通過
// Chinese.name = "張繼科";
c1.eat();
Chinese.show();
//編譯不通過
// Chinese.eat();
// Chinese.info();
}
}
//中國人
class Chinese{
String name;
int age;
static String nation;
public void eat(){
System.out.println("中國人吃中餐");
//呼叫非靜態結構
this.info();
System.out.println("name :" +name);
//呼叫靜態結構
walk();
System.out.println("nation : " + nation);
}
public static void show(){
System.out.println("我是一箇中國人!");
//不能呼叫非靜態的結構
// eat();
// name = "Tom";
//可以呼叫靜態的結構
System.out.println(Chinese.nation);
walk();
}
public void info(){
System.out.println("name :" + name +",age : " + age);
}
public static void walk(){
}
}
---------------------------------------練習1-------------------------------------
48.單例設計模式:
package com.atguigu.java2;
/*
* 單例設計模式:
* 1. 所謂類的單例設計模式,就是採取一定的方法保證在整個的軟體系統中,對某個類只能存在一個物件例項。
* 2. 如何實現?
* 餓漢式 vs 懶漢式
* 3. 區分餓漢式 和 懶漢式
* 餓漢式:
* 壞處:物件載入時間過長。
* 好處:餓漢式是執行緒安全的
* 懶漢式:好處:延遲物件的建立。
* 目前的寫法壞處:執行緒不安全。--->到多執行緒內容時,再修改
*/
public class SingletonTest1 {
public static void main(String[] args) {
// Bank bank1 = new Bank();
// Bank bank2 = new Bank();
Bank bank1 = Bank.getInstance();
Bank bank2 = Bank.getInstance();
System.out.println(bank1 == bank2);
}
}
//餓漢式
class Bank{
//1.私有化類的構造器
private Bank(){
}
//2.內部建立類的物件
//4.要求此物件也必須宣告為靜態的
private static Bank instance = new Bank();
//3.提供公共的靜態的方法,返回類的物件
public static Bank getInstance(){
return instance;
}
}
----------------------------------------------方式二--------------------------------------------
package com.atguigu.java2;
/*
* 單例模式的懶漢式實現
*/
public class SingletonTest2 {
public static void main(String[] args) {
Order order1 = Order.getInstance();
Order order2 = Order.getInstance();
System.out.println(order1 == order2);
}
}
class Order{
//1.私有化類的構造器
private Order(){
}
//2.聲明當前類物件,沒有初始化
//4.此物件也必須宣告為static的
private static Order instance = null;
//3.宣告public、static的返回當前類物件的方法
public static Order getInstance(){
if(instance == null){
instance = new Order();
}
return instance;
}
}
49.java程式碼塊:
package com.atguigu.java3;
/*
* 類的成員之四:程式碼塊(或初始化塊)
*
* 1. 程式碼塊的作用:用來初始化類、物件
* 2. 程式碼塊如果有修飾的話,只能使用static.
* 3. 分類:靜態程式碼塊 vs 非靜態程式碼塊
*
* 4. 靜態程式碼塊
* >內部可以有輸出語句
* >隨著類的載入而執行,而且只執行一次
* >作用:初始化類的資訊
* >如果一個類中定義了多個靜態程式碼塊,則按照宣告的先後順序執行
* >靜態程式碼塊的執行要優先於非靜態程式碼塊的執行
* >靜態程式碼塊內只能呼叫靜態的屬性、靜態的方法,不能呼叫非靜態的結構
*
* 5. 非靜態程式碼塊
* >內部可以有輸出語句
* >隨著物件的建立而執行
* >每建立一個物件,就執行一次非靜態程式碼塊
* >作用:可以在建立物件時,對物件的屬性等進行初始化
* >如果一個類中定義了多個非靜態程式碼塊,則按照宣告的先後順序執行
* >非靜態程式碼塊內可以呼叫靜態的屬性、靜態的方法,或非靜態的屬性、非靜態的方法
*
* 對屬性可以賦值的位置:
* 1.預設初始化
* 2.顯示初始化
* 3.構造器中初始化
* 4.有了物件之後,可以通過"物件.屬性"或者"物件.方法"的方式,進行賦值
* 5.在程式碼塊中賦值(先與構造器中的初始化執行)
*/
public class BlockTest {
public static void main(String[] args) {
String desc = Person.desc;
System.out.println(desc);
Person p1 = new Person();
Person p2 = new Person();
System.out.println(p1.age);
Person.info();
}
}
class Person{
//屬性
String name;
int age;
static String desc = "我是一個人";
//構造器
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//非static的程式碼塊
{
System.out.println("hello, block - 2");
}
{
System.out.println("hello, block - 1");
//呼叫非靜態結構
age = 1;
eat();
//呼叫靜態結構
desc = "我是一個愛學習的人1";
info();
}
//static的程式碼塊
static{
System.out.println("hello,static block-2");
}
static{
System.out.println("hello,static block-1");
//呼叫靜態結構
desc = "我是一個愛學習的人";
info();
//不可以呼叫非靜態結構
// eat();
// name = "Tom";
}
//方法
public void eat(){
System.out.println("吃飯");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
public static void info(){
System.out.println("我是一個快樂的人!");
}
}
---------------------------------------------練習1-------------------------------------------
package com.atguigu.java3;
//總結:由父及子,靜態先行
class Root{
static{
System.out.println("Root的靜態初始化塊");
}
{
System.out.println("Root的普通初始化塊"); //在呼叫構造方法時呼叫
}
public Root(){
super();
System.out.println("Root的無引數的構造器");
}
}
class Mid extends Root{
static{
System.out.println("Mid的靜態初始化塊");
}
{
System.out.println("Mid的普通初始化塊");
}
public Mid(){
super();
System.out.println("Mid的無引數的構造器");
}
public Mid(String msg){
//通過this呼叫同一類中過載的構造器
this();
System.out.println("Mid的帶引數構造器,其引數值:"
+ msg);
}
}
class Leaf extends Mid{
static{
System.out.println("Leaf的靜態初始化塊");
}
{
System.out.println("Leaf的普通初始化塊");
}
public Leaf(){
//通過super呼叫父類中有一個字串引數的構造器
super("尚矽谷");
System.out.println("Leaf的構造器");
}
}
public class LeafTest{
public static void main(String[] args){
new Leaf();
System.out.println();
new Leaf();
}
}
----------------------------------------------練習2---------------------------------------
package com.atguigu.java3;
/*
* 對屬性可以賦值的位置:
* ①預設初始化
* ②顯式初始化/⑤在程式碼塊中賦值(誰在前面就先執行誰)
* ③構造器中初始化
* ④有了物件以後,可以通過"物件.屬性"或"物件.方法"的方式,進行賦值
* 執行的先後順序:① - ② / ⑤ - ③ - ④
*/
public class OrderTest {
public static void main(String[] args) {
Order order = new Order();
System.out.println(order.orderId);
}
}
class Order{
int orderId = 3;
{
orderId = 4;
}
}
50.final關鍵字:
package com.atguigu.java3;
/*
* final:最終的
*
* 1. final可以用來修飾的結構:類、方法、變數
*
* 2. final 用來修飾一個類:此類不能被其他類所繼承。
* 比如:String類、System類、StringBuffer類
*
* 3. final 用來修飾方法:表明此方法不可以被重寫
* 比如:Object類中getClass();
*
* 4. final 用來修飾變數:此時的"變數"就稱為是一個常量
* 4.1 final修飾屬性:可以考慮賦值的位置有:顯式初始化、程式碼塊中初始化、構造器中初始化
* 4.2 final修飾區域性變數:
* 尤其是使用final修飾形參時,表明此形參是一個常量。當我們呼叫此方法時,給常量形參賦一個實參。一旦賦值
* 以後,就只能在方法體內使用此形參,但不能進行重新賦值。
*
* static final 用來修飾屬性:全域性常量
*/
public class FinalTest {
final int WIDTH = 0;
final int LEFT;
final int RIGHT;
// final int DOWN;
{
LEFT = 1;
}
public FinalTest(){
RIGHT = 2;
}
public FinalTest(int n){
RIGHT = n;
}
// public void setDown(int down){
// this.DOWN = down;
// }
public void doWidth(){
// width = 20;
}
public void show(){
final int NUM = 10;//常量
// NUM += 20;
}
public void show(final int num){
// num = 20;//編譯不通過
System.out.println(num);
}
public static void main(String[] args) {
int num = 10;
num = num + 5;
FinalTest test = new FinalTest();
// test.setDown(3);
test.show(10);
}
}
final class FinalA{
}
//class B extends FinalA{
//
//}
//class C extends String{
//
//}
class AA{
public final void show(){
}
}
class BB extends AA{
// public void show(){
//
// }
}
-------------------------------------面試題--------------------------------------
1. static 修飾的屬性,相較於例項變數,有哪些特別之處(>=3點)
隨著類的載入而載入;早於物件的建立;只要許可權允許,可以通過”物件.static屬性”的方式進行呼叫;存在於方法區的靜態域
2. final 可以用來修飾哪些結構,分別表示什麼意思
3. 程式碼實現單例模式的餓漢式
4. 程式碼實現單例模式的懶漢式 -目前還是執行緒不安全的。
5. 類的屬性賦值的位置有哪些?先後順序為何?
預設初始化
顯式初始化 、程式碼塊中初始化
構造器中初始化
通過”物件.屬性” 或”物件.方法”的方式賦值