Java類和物件知識點
Java類和物件
1.面向程式設計:我們再解決問題中,注重的是解決問題的每一個步驟和過程。
以計算機的角度去看待問題
2.面向物件:注重的是在為題中,設計的到哪些物件,以及物件之間有哪些關係
以自己的角度去看待問題
為什麼使用面向物件?/面向物件的好處:一點點東西的變化不會影響到整個程式,把錯誤的控制在一個區域性的範圍
核心思想 | 缺點 | 演算法 | |
面向程式設計 | 自項向下,逐步求精,也就是把功能分解 設計資料結構 編寫基礎程式碼,基於資料結構 | 一旦資料結構發生修改,可能必須就要修改操作的程式碼。 可重用性差 可維護性差,維護的成本高 | 程式=資料結構+演算法 |
相對的優點 | |||
面向物件 | 分解資料 資料和操作資料是一個整體 | 資料修改,只涉及這對該資料的操作(封裝) 可複用性強(繼承) 可維護性高,維護的成本低 | 程式=物件+訊息 |
萬事萬物皆物件,物件是由靜態的屬性和動態的方法來組成的類,是一組具有相同屬性和行為的物件的抽象。
訊息:物件之間的通訊和響應。
一..類和物件
三大特徵:封裝,繼承,多型
類的組成:成員變數和成員方法
1.封裝
定義: 存在一個邊界,邊界之內的細節隱藏起來,只留下對外的介面(如,筆記本,手機,飲水機)
為甚麼使用封裝?:(1)易用,簡單(2)安全(3)易維護
封裝的好處:
1.只能通過規定方法訪問資料
2.隱藏類的實現細節
3.方便加入控制語句
4.方便修改實現經過封裝的屬性,不能直接訪問,要通過公共屬性get/set方法訪問。
2.繼承
如何實現繼承:
在java語言中,用extends(擴充套件)關鍵字來表示一個類繼承了另一個類。
允許後代直接使用先輩的所有屬性和行為
為甚麼使用繼承:更好的實現程式碼的重用
3.多型
定義:相同的訊息傳送到不同的物件時,產生的響應不同
多型的體現:過載、重寫等
多型的前提
1. 必須是類與類之間有關係。要麼繼承,要麼實現。
2. 通常還有一個前提:存在覆蓋。
多型的好處:
1.可替換性(substitutability)。多型對已存在程式碼具有可替換性。例如,多型對圓Circle類工作,對其他任何圓形幾何體,如圓環,也同樣工作。
2.可擴充性(extensibility)。多型對程式碼具有可擴充性。增加新的子類不影響已存在類的多型性、繼承性,以及其他特性的執行和操作。實際上新加子類更容易獲得多型功能。例如,在實現了圓錐、半圓錐以及半球體的多型基礎上,很容易增添球體類的多型性。
3.介面性(interface-ability)。多型是超類通過方法簽名,向子類提供了一個共同介面,由子類來完善或者覆蓋它而實現的。如圖8.3所示。圖中超類Shape規定了兩個實現多型的介面方法,computeArea()以及computeVolume()。子類,如Circle和Sphere為了實現多型,完善或者覆蓋這兩個介面方法。
4.靈活性(flexibility)。它在應用中體現了靈活多樣的操作,提高了使用效率。
5.簡化性(simplicity)。多型簡化對應用軟體的程式碼編寫和修改過程,尤其在處理大量物件的運算和操作時,這個特點尤為突出和重要
1.過載overloading
1) 方法過載是讓類以統一的方式處理不同型別資料的一種手段。多個同名函式同時存在,具有不同的引數個數/型別。過載是一個類中多型性的一種表現。
2) Java的方法過載,就是在類中可以建立多個方法,它們具有相同的名字,但具有不同的引數和不同的定義。呼叫方法時通過傳遞給它們的不同引數個數和引數型別來決定具體使用哪個方法, 這就是多型性。
3) 過載的時候,方法名要一樣,但是引數型別和個數不一樣,返回值型別可以相同也可以不相同。無法以返回型別作為過載函式的區分標準。
overload(過載)
1、引數型別、個數、順序至少有一個不相同。
2、不能過載只有返回值不同的方法名。
3、存在於父類和子類、同類中。
示例程式碼:
public class Dog {
Dog() {
this.bark();
}
void bark()//bark()方法是過載方法
{
System.out.println("nobarking!");
this.bark("female",3.4);
}
void bark(String m,double l)//注意:過載的方法的返回值都是一樣的,
{
System.out.println("abarking dog!");
this.bark(5,"China");
}
void bark(int a,String n)//不能以返回值區分過載方法,而只能以“引數型別”和“類名”來區分
{
System.out.println("ahowling dog");
}
public static void main(String[]args)
{
Dog dog = new Dog();
//dog.bark();
//dog.bark("male","yellow");
//dog.bark(5, "China");
}
}
2)重寫overriding
1)父類與子類之間的多型性,對父類的函式進行重新定義。如果在子類中定義某方法與其父類有相同的名稱和引數,我們說該方法被重寫 (Overriding)。在Java中,子類可繼承父類中的方法,而不需要重新編寫相同的方法。但有時子類並不想原封不動地繼承父類的方法,而是想作一定的修改,這就需要採用方法的重寫。方法重寫又稱方法覆蓋。
2) 若子類中的方法與父類中的某一方法具有相同的方法名、返回型別和引數表,則新方法將覆蓋原有的方法。如需父類中原有的方法,可使用super關鍵字,該關鍵字引用了當前類的父類。
override(重寫)
1、方法名、引數、返回值相同。
2、子類方法不能縮小父類方法的訪問許可權。
3、子類方法不能丟擲比父類方法更多的異常(但子類方法可以不丟擲異常)。
4、存在於父類和子類之間。
5、方法被定義為final不能被重寫
6. 子類函式的訪問修飾許可權不能少於父類的;
示例程式碼:
public class Base
{
void test(int i)
{
System.out.print(i);
}
void test(byte b)
{
System.out.print(b);
}
}
public class TestOverriding extends Base
{
void test(int i)
{
i++;
System.out.println(i);
}
public static void main(String[]agrs)
{
Base b=new TestOverriding();
b.test(0)
b.test((byte)0)
}
}
這時的輸出結果是1 ,0,這是執行時動態繫結的結果。
總結:面向物件是一種很自然,樸素的方法,來源於生活。
二.引用:
Pointp = new Point();的含義是首先例項化一個物件(new Point()),然後定義一個引用,p指向這個例項,p = p1;並不是將例項p1賦值給例項p,而是改變了引用的關係。
棧:記憶體和地址 堆: new的物件(先進後出)
三.建構函式:
相當於初始化
建構函式,是在物件例項化時自動被系統呼叫,該函式名必須是獨一無二的。對與一個類來說,是將類名作為函式名。
建構函式不需要程式設計師去定義返回值,他是系統自動決定的,void也不行
四.關鍵字
1. Final關鍵字
Final修飾的方法不能被重寫
Final修飾的屬性不能被修改(也就是常量)
Final修飾的類不能被繼承
2. This關鍵字
this關鍵字是什麼意思?
有時一個方法需要引用呼叫它的物件。為此,java定義了this這個關鍵字。簡單地說,
This是在物件內部指代自身的引用。可以直接引用物件,可以解決例項變數和區域性變數之間發生的任何同名的衝突。
3. static 關鍵詞
沒有加static關鍵詞的成員變數只能面向這個物件,不能面向整個類
Static 靜態:靜態程式碼塊是在載入類的時候自動被執行,早於建構函式,靜態的方法,面向的是整個類,不是某個物件,所以沒有this,並且只能使用類名來呼叫,不能使用例項化物件去呼叫
private static int n1,n2;
如 n1++自增1,沒有static關鍵詞修飾就只會是1,不會自增1
五.抽象類
.抽象
提取事物的本質,共性的屬性和方法,忽略某些不必要的細節和個性的差異
為什麼使用抽象類?
在現實生活中,有些類我們明明知道是有某些方法的,但是具體這些方法是怎麼去做的好像又無法說清楚,比如手機、電報、固定電話等都是通訊工具,而通訊工具就應該具有向外傳送訊息的方法,但是卻無法說明具體怎麼發,而手機、電報等我們又可以說清楚他們是怎麼傳送訊息的
由於抽象類中包含有未實現的方法,所以抽象類是無法去例項化物件(new),那麼它的作用是什麼呢,它可以對它的後代進行規劃和約束,後代必須去按照它的要求去實現,但具體怎麼實現由後代去決定
抽象方法:
只有宣告,沒有實現。abstract修飾抽象方法
抽象類的特點:
1、抽象類不能直接例項化,並且對抽象類使用new 運算子是編譯時錯誤,他只能作為父類被繼承。雖然一些變數和值在編譯時的型別可以是抽象的,但是這樣的變數和值必須或者為null,或者含有對非抽象類的例項的引用(此非抽象類是從抽象類派生的)。2、允許(但不要求)抽象類包含抽象成員。3、抽象類不能被密封
,
作用是:
對後代進行規則,即凡是它的後代,必須實現他未實現的方法
比如說,形狀肯定有計算周長和麵積的方法,但是具體如何計算的,卻無法描述,三角形有三角形計算的方法,圓有圓計算的方法,所以在形狀這個類裡只能宣告這個方法,但是不能實現
子類繼承抽象父類必須要重寫,而繼承普通父類想重寫就重寫,不想重寫就不重寫
賦值相容性規則:
凡是需要使用父類物件的地方,都可以使用其公有子類去代替
如:凡是需要使用車(父類)的地方,都可以使用三輪車(子類)去代替
抽象類的使用原則:
· 1.抽象類必須有子類,子類利用extends關鍵字來繼承抽象類,一個子類只能夠繼承一個父類;
·2. 抽象類的子類(如果不是抽象類),那麼必須要重寫抽象類中的全部抽象方法;
3.抽象類可以利用物件的向上轉型機制(賦值相容性),通過子類物件進行例項化操作。
案例:
package類和物件.抽象類;
public abstract class Shape {
private Stringname;
public Shape(Stringname) {
this.name = name;
}
public StringgetName() {
returnname;
}
publicabstract double perimeter();
publicabstract double area();
}
三角形 子類
package類和物件.抽象類;
import java類和物件_案例.C201_02_02_座標類.Point;
public class Triangle extends Shape {
private Pointp1;
private Pointp2;
private Pointp3;
public Triangle(Stringname, Point p1, Point p2, Point p3) {
super(name);
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
}
public Triangle(Stringname,double x1,double y1,double x2,double y2,double x3,double y3){
super(name);
this.p1 = new Point(x1,y1);
this.p2= new Point(x2,y2);
this.p3 = new Point(x3,y3);
}
@Override
publicdouble perimeter() {
doubles1 = p1.distance(p2);
doubles2 = p2.distance(p3);
doubles3 = p3.distance(p1);
returns1+s2+s3;
}
@Override
publicdouble area() {
doubles1 = p1.distance(p2);
doubles2 = p2.distance(p3);
doubles3 = p3.distance(p1);
doublea=(s1+s2+s3)/2;
doublearea = Math.sqrt(a*(a-s1)*(a-s2)*(a-s3));
returnarea;
}
}
圓 子類
package類和物件.抽象類;
public class Circle extends Shape {
privatedouble r;
public Circle(Stringname, double r) {
super(name);
this.r = r;
}
@Override
publicdouble perimeter() {
doubleperimeter=Math.PI* r *2;
returnperimeter;
}
@Override
publicdouble area() {
doublearea = Math.PI*Math.pow(r,2);
returnarea;
}
@Override
publicString toString() {
return"Circle{" +
"r=" + r+
'}';
}
}
測試類
publicclass Test_shape {
publicstatic void main(String[] args) {
Shape shape1 = new Circle("圓",5);//賦值相容性規則
System.out.println(shape1.getName());
System.out.println(shape1.perimeter());
System.out.println(shape1.area());
shape1 = new Triangle("三角形",2,5,5,4,5,6);
System.out.println(shape1.area());
shape1 = new Square("正方形",5);
System.out.println(shape1.area());
}
}
六.介面
介面所有的方法都是抽象方法:所以在宣告方法時,關鍵詞abstract寫不寫都沒有關係了。
介面的定義關鍵詞是interface,抽象類是class。
抽象類是用來繼承(extends)的,介面是用實現(implements)的
匿名內部類:
為甚麼要使用匿名內部類
先看看如果不使用匿名內部類
(1)定義介面Shape
public interface Shape {
public String getName();
public double perimeter();
public double area();
}
(2)實現介面實現類Square
public class Square implements Shape{
private double d;
public Square(double d) {
this.d = d;
}
@Override
public String getName() {
return "正方形";
}
@Override
public double perimeter() {
return d*4;
}
@Override
public double area() {
return d*d;
}
}
(3)定義Square類物件並使用
public class Test_jiekou {
public static void main(String[] args) {
Square square = new Square(3);
Shape shape = square;
print(shape);
}
public static void print(Shape shape){
System.out.println(shape.getName()+"的周長是"+shape.perimeter()+"\n面積是"+shape.area());
}
}
那如果不使用匿名內部類呢?
(1) 定義介面(與上一種情形一樣)
(2) 定義匿名內部類,並實現介面(實際上就是將上一種情形的第2、3步給 合併了)
匿名內部類顯然簡化了流程,但是也使得使用者理解更加困難了,程式碼的層次不是太清晰。