面對對象的特征一:封裝與隐藏
一、問題的引入:
當我們建立一個類的對象以後,我們可以通過"對象.屬性"的方式,對對象的屬性進行指派。這裡,指派操作要受到
屬性的資料類型和存儲範圍的制約,除此之外,沒用其它的制約條件。但是,在實際問題中,我們往往需要給屬性指派
加入額外的限制條件。這個限制條件不能在屬性聲明時展現,我們隻能通過方法進行限制條件的添加。(比如setLegs)
同時,我們需要避免使用者再使用"對象.屬性"的方式對屬性進行指派。則需要将屬性聲明為私有的(private)
–>此時,針對于屬性就是展現封裝性。
二、封裝性的展現:
我們将類的屬性xxx私有化(private),同時設定,提供公共的(public)方法來擷取(getXxx)和設定(setXxx)此屬性的值
拓展:封裝性的展現:1、如上 2、不對外暴露的私有的方法 3、單例模式…
三、封裝性的展現,需要權限修飾符來配合
1.java規定的4種權限(從小到大排列):private、預設、protected、public
2.4種權限可以用來修飾類及類的内部結構:屬性、方法、構造器、内部類
3.具體的,4種權限都可以用來類的内部結構:修飾屬性、方法、構造器、内部類
修飾類的話,隻能使用:預設、public
總結封裝性:Java提供了4種權限修飾來修飾類及類的内部結構,展現類及類的内部結構在調用時的可見性的大小。
public class AnimalTest {
public static void main(String[] args) {
Animal a=new Animal();
a.name="花花";
a.age=1;
//a.legs=4; 不可見
a.show();
//a.legs=-4; 不可見
// a.setLegs(6);
a.setLegs(-6);
a.show();
}
}
class Animal{
String name;
int age;
private int legs;//腿的個數
//屬性的擷取
public int getLegs(){
return legs;
}
//屬性的設定
public void setLegs(int l){
if (l>=0&&l%2==0){
legs=l;
}else {
legs=0;
// 抛出一個異常(暫時沒講)
}
}
public void eat(){
System.out.println("動物進食");
}
public void show(){
System.out.println("name= "+name+",age= "+age+",legs="+legs);
}
//提供關于屬性age的get和set方法
public int getAge(){
return age;
}
public void setAge(int a){
age=a;
}
}
類的結構之三:構造器(或構造方法、constructor)的使用
construct:建設、建造 construction:CCB constructor:建設者
一、構造的作用:
1.建立對象
2.初始化對象的資訊
二、說明:
1.如果沒有顯式的定義類的構造器的話,則系統會預設提供一個空參的構造器
2.定義構造器的格式:權限修飾符 類名(形參清單){}
3.一個類中定義的多個構造器,彼此構成重載
4.一旦顯式的定義了類的構造器之後,系統就不在提供預設的空參構造器
5.一個類中,至少會有一個構造器
public class PersonTest {
public static void main(String[] args) {
//建立類的對象:new + 構造器
Person p =new Person();
p.eat();
Person p1=new Person("Tom");
System.out.println(p1.name);
}
}
class Person{
//屬性
String name;
int age;
//構造器
public Person(){
System.out.println("Person()....");
}
public Person(String n){
name=n;
}
public Person(String n,int a){
name=n;
age=a;
}
//方法
public void eat(){
System.out.println("人吃飯");
}
public void study(){
System.out.println("人可以學習");
}
}
JavaBean是一種Java語言寫成的可重用元件
所謂JavaBean,是指符合如下标準的Java類:
>類是公共的
>有一個無參的公共的構造器
>有屬性,且有對應的get、set方法
public class Customer {
private int id;
private String name;
public Customer(){
}
public void setId(int i){
id=i;
}
public int getId(){
return id;
}
public void setName(String n){
name=n;
}
public String getName(){
return name;
}
}
總結:屬性指派的先後順序
1.預設初始化
2.顯示初始化
3.構造器中初始化
4.通過"對象.方法" 或"對象.屬性"
以上操作的先後順序:1->2->3->4
public class UserTest {
public static void main(String[] args) {
User u=new User();
System.out.println(u.age);
User u1=new User(2);
u1.setAge(3);
System.out.println(u1.age);
}
}
class User{
String name;
int age=1;
public User(){
}
public User(int a){
age=a;
}
public void setAge(int a){
age=a;
}
}
this關鍵字的使用:
1.this可以用來修飾、調用:屬性、方法、構造器
2.this修飾屬性和方法
this了解為:目前對象 或目前正在建立的對象(構造器)
2.1在類的方法中,我們可以使用"this.屬性"或者"this.方法"的方式,調用目前對象屬性或方法。但是,通常情況下,我們都選擇省略"this."。特殊情況下,如果方法的形參和類的屬性同名時,我們必須顯示的使用"this.變量"的方式,表明此變量是屬性,而非形參。
2.2 在類的構造器中,我們可以使用"this.屬性"或者"this.方法"的方式,調用目前正在建立的對象屬性或方法。但是,通常情況下,我們都選擇省略"this."。特殊情況下,如果構造器的形參和類的屬性同名時,我們必須顯示的使用"this.變量"的方式,表明此變量是屬性,而非形參。
3.this調用構造器
1、我們在類的構造器中,可以顯式的使用"this(形參清單)"方式,調用本類中指定的其它構造
2、構造器中不能通過"this(形參清單)“方式調用自己
3、如果一個類中有n個構造器,則最多有n-1構造器中使用了"this(形參清單)”
4、規定:"this(形參清單)“必須聲明在目前構造器的首行
5、構造器内部:最多隻能聲明一個"this(形參清單)”,用來調用其它的構造器
public class thisTset {
public static void main(String[] args) {
ThisPerson t=new ThisPerson();
t.setAge(1);
System.out.println(t.getAge());
t.eat();
System.out.println();
ThisPerson t2=new ThisPerson("Jerry",20);
System.out.println(t2.getAge());
}
}
class ThisPerson{
//屬性
private String name;
private int age;
//構造器
public ThisPerson(){
this.eat();
//ThisPerson初始化時,需要考慮如下的1,2,3,4...(共40行代碼)
String info="ThisPerson初始化時,需要考慮如下的1,2,3,4...(共40行代碼)";
System.out.println(info);
}
public ThisPerson(String name){
this();
//this 目前正在建立的對象
this.name=name;
}
public ThisPerson(int age){
this();
this.age=age;
// this();
}
public ThisPerson(String name,int age){
this(age);
this.name=name;
//this.age=age;
}
//方法
public void setName(String name){
this.name=name;
}
public String getName(){
return this.name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return this.age;
}
public void eat(){
System.out.println("eat");
this.study();
}
public void study(){
System.out.println("study");
}
}
一、package關鍵字的使用
1.為了更好的實作項目中類的管理,提供包的概念
2.使用package聲明類或接口所屬的包,聲明在源檔案的首行
3.包,屬于辨別符,遵循辨別符的命名規則、規範(xxxxyyyyyzzz)、“見名知意”
4.每"."一次,就代表一層檔案目錄
補充:同一個包下,不能命名相同名的接口、類
不同的包下,可以命名相同名的接口、類
二、import關鍵字的使用
import:導入
1.在源檔案中顯示的使用import結構導入指定包下的類、接口
2.聲明在包的聲明和類的聲明之間
3.如果需要導入多個結構,則并列寫出即可
4.可以使用"xxx."的方式,表示可以導入xxx包下所有結構
5.如果使用的類或接口是java.lang包下定義,則可以省略import結構
6.如果使用的類或接口是本包下定義,則可以省略import結構
7.如果在源檔案中,使用了不同包下的同名的類,則必須至少有一個類需要以全類名的方式顯示。
8.如果使用"xxx."方式表明可以調用xxx包下的所有結構。但是如果使用的是xxx包下的結構,則仍需要顯式的導入
9.import static:導入指定類或者接口中的靜态結構:屬性或者方法。
面對對象的特征之二:繼承性
一、繼承性的好處:
1.減少了代碼的備援,提高了代碼的複用性
2.便于功能的擴充
3.為之後多态的使用,提供了前提
二、繼承性的格式:class A extends B{}
A:子類、派生類、subclass
B:父類、超類、幾類、superclass
2.1展現:一旦子類A繼承父類B以後,子類A中就擷取了父類B中聲明的結構:屬性、方法
特别的:父類中聲明為private的屬性或方法,子類繼承父類以,仍然認為擷取了父類中私有的結構,隻因為封裝性的影響,使得子類不能直接調用父類的結構而已。
2.2子類繼承父類以後,還可以聲明自己特有的屬性和方法,實作功能的拓展子類和父類的關系,不同于集合和集合的關系。
extends:延展、拓展
三、java中關于繼承的規定:
1.一個類可以被多個子類繼承
2.java中類的單繼承性:一個類隻能有一個父類
3.子父類是相對的概念。
4.子類直接繼承的父類,稱為:直接父類。間接繼承的父類稱為:簡介父類
5.子類繼承父類以後,就擷取了直接父類以及所有間接父類中聲明的屬性和方法
四、
1.如果我們沒用顯式的聲明一個類的父類的話,則此類繼承于java.lang.Object類
2.所有的java類(除了java.lang.Object類除外)都直接或者間接的繼承于java.lang.Object類
3.意味着,所有的java類具有java.lang.Object類聲明的功能
方法的重寫(override/overwrite)
1.重寫:子類繼承父類以後,可以對父類種同名同參數的方法,進行覆寫操作
2.應用:重寫以後,當建立子類對象以後,通過子類對象調用父類中的同名同參數的方法時,實際執行的是子類重寫父類的方法。
3.重寫的規定:
方法的聲明:權限修飾符 傳回值類型 方法名(形參清單)throws 異常的類型{
//方法體
}
約定俗稱:子類中叫重寫的方法,父類中叫被重寫的方法
1.子類重寫的方法的方法名和形參清單與父類被重寫的方法的方法名和形參清單相同
2.子類重寫的方法的權限修飾符不小于父類被重寫的方法的權限修飾符
>特殊情況:子類不能重寫父類中聲明為private權限的方法
3.傳回值類型:
>父類被重寫的方法傳回值類型是void,則子類重寫的方法的傳回值類型隻能是void
>父類被重寫的方法傳回值類型是A類型,則子類重寫的方法的傳回值類型可以是A類或A類的子類
>父類被重寫的方法傳回值類型是基本資料類型(比如:double),則子類重寫的方法的傳回值類型必須是相同的基本資料類型(必須也是double)
4.子類重寫的方法抛出的異常類型不大于父類被重寫的方法抛出的異常類型(具體放到異常處理的時候講)
注:子類和父類中同名同參數的方法要麼都聲明為非static的(考慮重寫),要麼都聲明為static的(不是重寫)。
面試題:區分方法的重載與重寫
public class Person {
String name;
int age;
int id=1001;//身份證号
public Person(){
System.out.println("我無處不在");
}
public Person(String name){
this.name=name;
}
public Person(String name,int age){
//this.name=name;
this(name);
this.age=age;
}
public void eat(){
System.out.println("吃飯");
}
public void walk(int distance){
System.out.println("走路,走的距離是: "+distance+"公裡");
this.show();
}
private void show(){
System.out.println("父");
System.out.println(name);
}
public Object info(){
return null;
}
public double info1(){
return 1.0;
}
}
public class Student extends Person{
String major;
int id=1002;//學号
public Student(){
super();
}
public Student(String major){
super();
this.major=major;
}
public Student(String name,int age,String major){
// this.name=name;
// this.age=age;
super(name,age);
this.major=major;
}
public void study(){
System.out.println("學習,專業是: "+major);
this.eat();
super.eat();
}
//對父類種的eat()進行重寫
public void eat(){
System.out.println("學生應該多吃有營養的食物");
}
public void show(){
System.out.println("子");
System.out.println("name = "+this.name +",age= "+super.name);
System.out.println("id= "+this.id);
System.out.println("id= "+super.id);
}
public String info(){
return null;
}
// public int info1(){
// return 1;
// }
}
public class PersonTest {
public static void main(String[] args) {
Student s=new Student("計科");
s.eat();
s.walk(10);
s.study();
System.out.println("************************");
Person p1=new Person();
p1.eat();
}
}
super關鍵字的使用
1.super了解為:父類的
2.super可以用來調用:屬性、方法、構造器
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類中的空參構造器為止,正因為加載過所有的父類結構,所有才可以看到記憶體中有父類中的結構,子類對象才可以考慮進行調用
明确:雖然建立子類對象時,調用了父類的構造器,但是自始至終就建立過一個對象,即為new的子類對象
面向對象特征之三:多态性
1.了解多态性:可以了解為一個事物的多種形态
2.何為多态性:
對象的多态性:父類的引用指向子類的對象(或子類的對象賦給父類的引用)
3.多态的使用:虛拟方法調用
有了對象的多态性以後,我們在編譯期,隻能調用父類中聲明的方法,但在運作期,我們實際執行的是子類重寫父類的方法
總結:編譯,看左邊; 運作,看右邊
4.多态性的使用前提:1.類的繼承關系 2.方法的重寫
5.對象的多态性隻适用于方法,不适用于屬性(編譯運作都看左邊)
public class Person {
String name;
int age;
int id=1001;
public void eat(){
System.out.println("人,吃飯");
}
public void walk(){
System.out.println("人,走路");
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
return age == person.age &&
id == person.id &&
Objects.equals(name, person.name);
}
}
public class Woman extends Person {
boolean isBeauty;
public void goShopping(){
System.out.println("女人喜歡購物");
}
public void eat(){
System.out.println("女人少吃,為了減肥");
}
public void walk(){
System.out.println("女人窈窕的走路");
}
}
public class Man extends Person {
boolean isSmoking;
int id=1002;
public void earnMoney(){
System.out.println("男人負責賺錢養家");
}
public void eat(){
System.out.println("男人多吃肉,長肌肉");
}
public void walk(){
System.out.println("男人霸氣的路");
}
}
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是Person類型
//p2.earnMoney();
p2.name="Tom";
System.out.println(p2.id);//1001
//有了對象的多态性以後:記憶體中實際上是加載了子類特有的屬性和方法的,但是由于變量聲明為父類類型,導緻
// 編譯時,隻能調用父類中聲明的屬性和方法。子類特有的屬性和方法不能調用。
//如何才能調用子類特有的屬性和方法?
//向下轉型:使用強制類型轉換符
Man m1=(Man)p2;
m1.earnMoney();
m1.isSmoking=true;
//使用強轉時,可能出現ClassCastException的異常
// Woman w1=(Woman)p2;
// w1.goShopping();
/**
* instanceof
*
* a instanceof 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**************");
}
//練習:
//問題一:編譯時通過,運作時不通過
//舉例一:
// Person p3=new Woman();
// Man m3=(Man)p3;
//舉例二:
// Person p4=new Person();
// Man m4=(Man)p4;
//問題二:編譯時通過,運作時也通過
Object obj=new Woman();
Person p=(Person)obj;
//問題三:編譯不通過
// Man m5=new Woman();
// String str=new Data();
}
}
== 和equal() 的差別
一、回顧==的使用
1,可以使用在基本資料類型變量和引用資料類型變量中
2.如果比較的是基本資料類型變量:比較兩個變量儲存的資料是否相等。(不一定類型要相同)
如果比較的是引用資料類型變量:比較兩個對象的位址值是否相同,即兩個引用是否指向同一個對象實體
補充:==符号使用時,必須保證符号左右兩邊的變量類型一緻
二、equals()方法的使用:
1.是一個方法,而非運算符
2.隻适用于引用資料類型
3.Object類中equals()的定義:
public boolean equals(Object obj){
return (this==obj)
}
說明:Object類中定義的equals()和==的作用是相同,比較兩個對象位址值是否相同,即兩個引用是否指向同一個對象
4.像String、Data、File、包裝類等都重寫了Object類中的equals()方法,重寫以後,
比較的不是兩個引用的位址值,而是比較兩個對象的"實體内容"是否相同
5.通常情況下,我們自定義的類如果适用equals()的話,也通常是比較兩個對象的"實體内容"是否相同,
那麼,我們就需要對Objects類中的equals()進行重寫
重寫的規則:比較兩個對象的内容是否相同
public class EqualTset {
public static void main(String[] args) {
int i=10;
int j=10;
double d=10.0;
System.out.println(i==j);
System.out.println(i==d);
if ("1".equals("1")){}
}
}
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 Person {
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 Person(){
}
public Person(String name,int age){
this.name=name;
this.age=age;
}
public void eat(){
System.out.println("吃飯");
}
public void sleep(){
System.out.println("睡覺");
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class ToStringTest {
public static void main(String[] args) {
Person person=new Person("Tom",21);
System.out.println(person.toString());//[email protected]
System.out.println(person);//[email protected]
String str=new String("MM");
System.out.println(str);//MM
Date date=new Date(21321321312L);
System.out.println(date.toString());
}
}
java.lang.Object類
1.Object類是所有java類的根父類
2.如果在類的聲明中使用的extends關鍵字指明其父類,則預設父類為java.lang.Object類
3.Object類中的功能(屬性、方法)就具有通用性。
屬性;無
方法: equals() /toString() /getClass /hashCode()/ clone() /finalize()
wait() /notify() /notifyAll()
4.Object類隻聲明了一個空參構造器+
面試題:
final、finally、finalize的差別
java中的JUnit單元測試
步驟:
2,建立java類,進行單元測試。
此時的java類要求:
1、此類是public的 2、此類提供公共的無參的構造器
3.此類中聲明單元測試方法。
此時的單元測試方法:方法的權限是public,沒有傳回值,沒有形參
4,此單元測試方法上需要聲明注解:@Test,并在單元測試類中導入:import org.junit.Test
5.聲明好單元測試方法以後,就可以在方法體内測試相關的代碼。
說明:
1.如果執行結果沒有任何異常:綠條
2.如果執行結果出現異常:紅條
public class JUnitTest {
int num=10;
@Test
public void testEquals(){
String s1="MM";
String s2="MM";
System.out.println(s1.equals(s2));
System.out.println(num);
show();
}
public void show(){
num = 20;
System.out.println("----");
}
@Test
public void testToString(){
String s2="MMMM";
System.out.println(s2.toString());
}
}
包裝類的使用:
1.java提供了8種基本類型對應的包裝類,使得基本資料類型的變量具有類的特征
2.掌握的:基本資料類型、包裝類、String三者之間的轉換
public class WrapperTest {
//String類型--->基本資料類型、包裝類:調用包裝類的parseXxx()
@Test
public void test5(){
String str1="123";
// int num1=(int)str1;
// Integer in1=(Integer)str1;
int num2 = Integer.parseInt(str1);
System.out.println(num2+1);
}
//基本資料類型、包裝類--->String類型,調用String重載的valueOF(Xxx xxx)
@Test
public void test4(){
int num1=10;
//方式1:連接配接運算
String str1=num1+"";
//方式二:調用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(str3);
}
/**
* JDK 5.0新特性:自動裝箱與自動拆箱
*/
@Test
public void test3(){
// int num1=10;
// //基本資料類型-->包裝類的對象
// method(num1);
//自動裝箱:基本資料類型---->包裝類
int num2=10;
Integer in1=num2;//自動裝箱
//自動拆箱:包裝類---->基本資料類型
System.out.println(in1.toString());
int num3=in1;
}
public void method(Object obj){
}
//包裝類---->基本資料類型:調用包裝類的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;
Integer in1=new Integer(num1);
System.out.println(in1.toString());
//報異常
// Integer in2=new Integer("abc"); //"123"才行
// System.out.println(in2.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);//true
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;
}
}