前言
面向對象在百度百科中是這樣解釋的:“面向對象是一種對現(xiàn)實世界理解和抽象的方法,是計算機編程技術發(fā)展到一定階段后的產(chǎn)物”套鹅。說的好像很流弊的樣子站蝠,看看就行。
包的認識
1.1:包的概念
包是組織卓鹿、整合類的一種方式
其目的在于保證使用類的唯一性(同一個包中菱魔,里面所包含的類名是唯一的)
比如在包A中定義了一個Test類,在包B中也定義了一個Test類吟孙,那么當使用A中的Test類時便導入包A調(diào)用A中的Test類(A.Test)澜倦,以此保證類的唯一性。
1.2:導入包中的類
Java中有很多現(xiàn)成的包供我們使用杰妓,使用這些包的方式有兩種
public class TestDemo {
public static void main(String[] args) {
java.util.Date time = new java.util.Date();
//使用 util 包中的Date類創(chuàng)建一個對象
System.out.println(time.getTime());
//調(diào)用該對象的 getTime 方法藻治,獲得一個毫秒級別的時間戳
}
}
上述代碼中,util 就是一個包巷挥,Date就是該包中的一個類桩卵,使用時用 java.包名.類名 使用
import java.util.Date;
public class TestDemo {
public static void main(String[] args) {
Date time = new Date();
System.out.println(time.getTime());
}
第一個代碼每次使用類時都要加包的前綴,太過麻煩倍宾,因此還可使用第二種方式雏节,在代碼最開頭使用 import 關鍵字導入需要的包,這樣就可以像使用自己定義的類一樣高职,直接用類名創(chuàng)建對象
當同時需要同一個包中的多個類是钩乍,可以用 import.java.包名.* 的方式導入包,這樣就可以使用該包下的所有類(但建議不要這么使用怔锌,否則當導入多個包時還是會出現(xiàn)類名重復的現(xiàn)象)寥粹。
1.3:靜態(tài)導入
包中除了類的普通方法外,還有一些靜態(tài)方法产禾,使用這些方法時排作,可以使用 import static 的方式導入包中的靜態(tài)字段和方法,無需創(chuàng)建對象直接使用
import static java.lang.Math.*;
public class TestDemo {
public static void main(String[] args) {
double x = 10.5;
double y = 3.0;
double result = sqrt(pow(x,y)+pow(x,y));
System.out.println(result);
}
1.4:自定義類放入包中
基本規(guī)則
- 在文件的最上方加一個 package 語句指定該代碼在哪個包中
- 包名盡量指定成唯一名字亚情,防止多文件間沖突
- 包名和代碼路徑相匹配
- 如果一個類沒有 package 語句妄痪,則該類會被放到默認包中
1.5:包的訪問權限控制
如果某個成員不包含 public 和 private 關鍵字,此時這個成員可以被包中的其他類使用楞件,但不能在包外部類中使用
1.6:常見的系統(tǒng)包
1衫生、java.lang:系統(tǒng)常用基礎類(String裳瘪,Object)挺举,jdk1.1以后自動導入
2慎宾、java.lang.reflect: java 反射編程包
3桐磁、java.net:進行網(wǎng)絡編程開發(fā)包
4驼鞭、java.sql:進行數(shù)據(jù)庫開發(fā)的支持包。
5蝎困、java.util:是java提供的工具程序包离赫。(集合類等)
6坚踩、java.io:I/O編程開發(fā)包墓阀。
繼承
2.1 概念:
當創(chuàng)建多個類時發(fā)現(xiàn)這些類之間存在一定的關聯(lián)關系毡惜,則可以創(chuàng)建一個父類擁有這些類的相同屬性和方法,讓這些類繼承與父類斯撮,來提高效率经伙,達到代碼重用的效果。
此時被繼承的類我們成為 父類勿锅、基類或者超類帕膜,而繼承的類我們稱為子類或者派生類,子類會繼承父類除構造方法外的其他所有東西溢十。
2.2 語法規(guī)則:
class 子類 extend 父類{
}
- 子類使用 extend 關鍵字繼承父類
- Java中一個子類只能繼承一個父類
- 子類會繼承父類的所有 public 的字段和方法
- 對于父類的 private 的字段和方法垮刹,子類無法訪問
- 子類實例中也包含父類實例,可使用 super 關鍵字得到父類的引用
class Animal{
public String name;//父類的name必須為 public 否則子類將無法訪問
public Animal(String name) {
this.name = name;
}
public void eat(String food){
System.out.println(this.name+"吃"+food);
}
}
class Dog extends Animal{
public Dog(String name){
super(name);
}
}
class Bird extends Animal{
public Bird(String name){
super(name);
}
public void fly(){
System.out.println(this.name+"正在飛");
}
}
public class TestDemo {
public static void main(String[] args) {
Dog dog = new Dog("旺旺");
dog.eat("骨頭");
Bird bird = new Bird("啾啾");
bird.eat("米粒");
bird.fly();
}
2.3茶宵、protected關鍵字
上述代碼中危纫,如果將父類的 name 設為 private子類將無法訪問宗挥,但設為 public 又違背了封裝的規(guī)則乌庶,此時就需要用到 protect 關鍵字
- 對于其他類的調(diào)用者來說,被 protect 修飾的字段和方法是不能被訪問的
- 但對于 該類的子類 和 同一個包下的其他類 來說契耿,被 protect 修飾的字段和方法是可以被訪問的
小結:Java中對字段和方法共有四種訪問權限
- private:只能在類內(nèi)部訪問瞒大,內(nèi)外部一律不行
- 默認:在類內(nèi)部能訪問,同一個包中的類也可以訪問
- protect:在類內(nèi)部能訪問搪桂,且在其子類和同一個包中的類也可以訪問
- public:類內(nèi)部和類的調(diào)用者都能訪問
2.4透敌、final關鍵字
final 可以修飾一個變量或者字段,用來表示常量
final 也惡意修飾一個類踢械,用來表現(xiàn)該類不能被繼承
組合:
即一個類中對另一個類的嵌套酗电,在一個類中實例另一個類,達到代碼重用的效果
多態(tài)
3.1内列、向上轉型:
如上代碼撵术,創(chuàng)建一個 Bird 的對象可以寫成
Bird bird = new Bird();
也可以寫成
Bird bird = new Bird()话瞧;
Animal bird2 = bird嫩与;
Animal bird3 = new Bird()寝姿;
此時bird2、bird3是一個父類(Animal)的引用划滋,指向子類(bird)的實例饵筑,這稱為向上轉型。
向上轉型發(fā)生的時機:
- 直接賦值(即上述代碼演示)
- 方法傳參
- 方法返回
方法傳參:
public static void main(String[] args) {
Bird bird = new Bird("啾啾");
feed(bird);
}
public static void feed(Animal animal){
animal.eat("谷子");
}
此時形參的類型是 Animal(父類) ,實際上是對應到 Bird(子類)的實例
方法返回:
public static void main(String[] args) {
findAnimal().eat("谷子");
}
public static Animal findAnimal(){
Bird bird = new Bird("啾啾");
return bird;
}
方法 findAnimal 返回值是 Animal 的一個引用处坪,但實際指向 Bird 的一個實例
3.2:動態(tài)綁定
子類和父類出現(xiàn)同名方法時發(fā)生
class Animal{
public String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food){
System.out.println("我是一只小動物");
System.out.println(this.name+"正在吃"+food);
}
}
class Bird extends Animal{
public Bird(String name){
super(name);
}
public void eat(String food){
System.out.println("我是一只小鳥");
System.out.println(this.name+"正在吃"+food);
}
public void fly(){
System.out.println(this.name+"正在飛");
}
}
public class TestDemo {
public static void main(String[] args) {
Animal animal1 = new Animal("動物");
Animal animal2 = new Bird("小鳥");
animal1.eat("谷子");
animal2.eat("谷子");
}
執(zhí)行以上代碼我們發(fā)現(xiàn):
- animal1 和 animal2 雖然都是 Animal 類型的引用根资,但animal1指向 Animal 實例的對象,animal2指向 Bird 實例的對象
- 對 animal1 和 animal2 分別調(diào)用eat方法同窘,發(fā)現(xiàn) animal1 調(diào)用的是父類的方法嫂冻,animal2 調(diào)用的是子類的方法
在Java中,調(diào)用某個方法塞椎,究竟執(zhí)行哪段代碼(是父類方法還是子類)桨仿,取決于看這個引用指向的對象是父類對象還是子類對象,這個過程是在運行時才決定的案狠,因此成為動態(tài)綁定
父類引用服傍,引用子類對象時,只能訪問自己特有的骂铁,不能訪問子類獨有的
3.3吹零、重寫
對于上述代碼,父類和子類的eat方法來說拉庵,就構成了重寫
重寫的注意事項:
- 普通方法可以重寫灿椅,static 修飾的方法不能重寫
- 重寫中子類的訪問權限不能低于父類的訪問權限
- 重寫和重載不同
重寫和重載的區(qū)別
1.要求不同
重載:a.方法名相同 b.參數(shù)列表不同 c.返回值不做要求
重寫:a.方法名相同 b.參數(shù)列表相同(參數(shù)類型和個數(shù)) c.返回值也要相同
2.范圍不同
重載:同一個類中
重寫:繼承關系,不同類中
3.限制
重載:無限制
重寫:子類中重寫的方法訪問權限不能低于父類的訪問權限
3.4钞支、理解多態(tài)
class Shape {
public void draw(){
}
}
class Circle extends Shape{
public void draw(){
System.out.println("畫一個圓圈○");
}
}
class Rectangle extends Shape{
public void draw(){
System.out.println("畫一個矩形□");
}
}
class Triangle extends Shape{
public void draw(){
System.out.println("畫一個三角△");
}
}
//================================================
//================================================
public class TestDemo {
public static void main(String[] args) {
Shape shape1 = new Circle();
Shape shape2 = new Rectangle();
Shape shape3 = new Triangle();
drawMap(shape1);
drawMap(shape2);
drawMap(shape3);
}
public static void drawMap(Shape shape){
shape.draw();
}
以上代碼茫蛹,分割線以上是由類的實現(xiàn)者編寫的,分割線以下是由類的調(diào)用者編寫的
當調(diào)用者編寫drawMap方法的時候(參數(shù)類型為父類Shape)烁挟,并不關心當前shape引用指向哪個類型的實例婴洼,此時shape調(diào)用的draw方法只取決于shape指向的哪個類型的實例,以實現(xiàn)不同的表現(xiàn)形式撼嗓,這種思想叫做多態(tài)柬采。
3.5、向下轉型
父類引用且警,引用子類對象稱為向上轉型粉捻;子類引用,引用父類對象稱為向下轉型斑芜。
class Animal{
public String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food){
System.out.println("我是一只小動物");
System.out.println(this.name+"正在吃"+food);
}
}
ass Bird extends Animal{
public Bird(String name){
super(name);
}
public void eat(String food){
System.out.println("我是一只小鳥");
System.out.println(this.name+"正在吃"+food);
}
public void fly(){
System.out.println(this.name+"正在飛");
}
}
public class TestDemo {
public static void main(String[] args) {
Animal animal = new Bird("啾啾");
animal.eat("谷子");
animal.fly();//執(zhí)行該行代碼時肩刃,會報錯誤
}
編譯過程中 animal 的類型時 Animal ,編譯器編譯時根據(jù)類型只知道 animal 中只有一個eat方法,找不到fly方法
- 編譯器檢查存在哪些方法時候树酪,看的是 Animal 類型
- 執(zhí)行時究竟執(zhí)行父類方法還是子類方法浅碾,看的是 Bird 類型
但很多時候為了讓向下轉型更安全,需要判斷一下 animal 是否指向 Bird 的引用续语,使用instanceof 關鍵字判斷
Animal animal = new Cat("小貓");
if (animal instanceof Bird) {
Bird bird = (Bird)animal;
bird.fly();
}
3.6垂谢、super關鍵字
當在子類內(nèi)部要調(diào)用父類方法時,就要用到 super 關鍵字
super 表示獲取到父類實例的引用疮茄,其有兩種常用方法
一滥朱、使用 super 來調(diào)用父類的構造方法,super(參數(shù))
public Bird(String name){
super(name);
}
二力试、使用 super 來調(diào)用父類的普通方法徙邻,super.方法名(參數(shù))
class Bird extends Animal{
public Bird(String name){
super(name);
}
public void eat(String food){
super.eat(food);
System.out.println("我是一只小鳥");
System.out.println(this.name+"正在吃"+food);
}
}
上述代碼中個,如果直接調(diào)用eat方法畸裳,則被編譯器認為是調(diào)用子類的方法(同遞歸)缰犁,想要調(diào)用父類方法則需要使用 super 關鍵字
this和super的區(qū)別:
1、概念
this:訪問本類的屬性和方法
super:訪問父類的屬性和方法
2怖糊、查找范圍
this:先查找本類帅容,子類沒有再調(diào)用父類
super:不查找本類,直接調(diào)用父類
3伍伤、特殊
this:表示當前對象的引用
super:表現(xiàn)父類對象的引用
多態(tài)存在的意義就在于并徘,讓調(diào)用者不必關注對象的具體類型,降低用戶的使用成本
4扰魂、抽象類
4.1語法規(guī)則
類似于之前代碼的父類 Shape 中的draw方法麦乞,其中并沒有實際工作,而由其子類重新該方法實現(xiàn)劝评,那么像這種沒有實際工作的方法我們就可以用 abstract 關鍵字修飾把它設計成一個抽象方法姐直,而包含抽象方法的類我們就稱為抽象類
abstract class Shape {
abstract public void draw();
}
- 在draw方法前加一個 abstract 修飾表示該方法是抽象方法,抽象方法沒有方法體
- 對于包含抽象方法的類付翁,class 前必須加一個 abstract 關鍵字表示是抽象類
注意事項:
- 抽象類不能直接實例
- 抽象方法的訪問權限不能是private
- 抽象類中可以包含其他非抽象方法简肴,也可以包含字段晃听,和普通方法一樣百侧,可以被重新可以被調(diào)用
4.2抽象類的作用
抽象類的意義在于為了被繼承
抽象類本身不能實例化,想要使用能扒,必須創(chuàng)建該抽象類的子類佣渴,在子類中重寫抽象方法
使用抽象類相當于多了一重編譯器的檢驗(對于抽象了來說,如果繼承的子類不重寫父類的抽象方法初斑,則會報錯)
5辛润、接口
接口是比抽象類還抽象,接口只包含抽象方法见秤,其字段也只能包含靜態(tài)常量
interface IShape{
abstract public void draw();
}
class Circle implements Shape{
@Override
public void draw() {
System.out.println();
}
}
- 用 interface 定義一個接口
- 接口中的方法只能是抽象方法砂竖,所以可以省略 abstract
- 并且接口中的方法只能是 public 真椿,所以可以省略
- Circle 用 implement 來實現(xiàn)接口
- 在調(diào)用的時候同樣可以創(chuàng)建一個接口的引用,對應到一個子類的實例
- 接口不能被單獨實例化
在Java中一個類只能繼承一個父類乎澄,但同時可以實現(xiàn)多個接口
class Animal{
public String name;
public Animal(String name){
this.name = name;
}
}
interface IFlying{
void fly();
}
interface IRunning{
void run();
}
interface ISwimming{
void swim();
}
class Dog extends Animal implements IRunning{
public Dog(String name){
super(name);
}
@Override
public void run() {
System.out.println(this.name+"正在跑步");
}
}
class Frog extends Animal implements IRunning,ISwimming{
public Frog(String name){
super(name);
}
@Override
public void run() {
System.out.println(this.name+"正在跑步");
}
@Override
public void swim() {
System.out.println(this.name+"正在游泳");
}
}
class Duck extends Animal implements IRunning,ISwimming,IFlying{
public Duck(String name){
super(name);
}
@Override
public void fly() {
System.out.println(this.name+"正在飛");
}
@Override
public void run() {
System.out.println(this.name+"正在游泳");
}
@Override
public void swim() {
System.out.println(this.name+"正在游泳");
}
}
public class TestDemo {
public static void main(String[] args) {
Dog dog = new Dog("汪汪");
Frog frog = new Frog("呱呱");
Duck duck = new Duck("嘎嘎");
dog.run();
frog.run();
frog.swim();
duck.fly();
duck.run();
}
}
接口使用實例——給對象數(shù)組排序
創(chuàng)建一個學生類
class Students implements Comparable{
private String name;
private int score;
public Students(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "Students{" +
"name='" + name + '\'' +
", score=" + score +
'}';
}
@Override
public int compareTo(Object o) {
Students s = (Students)o;
if(s.score > ((Students) o).score){
return 1;
}else if(s.score == ((Students) o).score){
return 0;
}else{
return -1;
}
}
}
在 sort 方法中會自動調(diào)用 compareTo 方法.compareTo 的參數(shù)是 Object突硝,其實傳入的就是Students類型的對象,然后比較當前對象和參數(shù)對象的大小關系
接口間的承接
一個接口可以承接另一個接口置济,達到復用效果解恰,使用 extends 關鍵字
接口間承接相當于把多個接口憑借在一起
Clonable 接口和深拷貝
Object 類中存在一個 clone 方法,調(diào)用這個方法可以創(chuàng)建一個對象的“拷貝”浙于,但是想要合法的調(diào)用clone方法护盈,必須先要實現(xiàn) Clonable 接口,否則就會拋出 CloneNotSupportedException 異常
class Person implements Cloneable{
public String name;
public Person(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
public class TestDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Person person1 = new Person("小明");
Person person2 = (Person) person1.clone();
person2.name = "小紅";
System.out.println(person1);
System.out.println(person2);
}
}
如下代碼即深拷貝:
class Money implements Cloneable{
public int m=10;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Person implements Cloneable{
public String name;
public Money money ;
public Person(String name) {
this.name = name;
this.money = new Money();
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
person.money = (Money) this.money.clone();
return person;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", money=" + money.m +
'}';
}
}
public class TestDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Person person1 = new Person("小明");
Person person2 = (Person) person1.clone();
person2.name = "小紅";
person2.money.m = 15;
System.out.println(person1);
System.out.println(person2);
}
}
總結
- 抽象類和接口都是Java中多態(tài)的常見使用方法羞酗,但兩者又有區(qū)別
最核心區(qū)別:抽象類可以包含普通方法和普通字段腐宋,可以被子類直接使用,而接口中只有抽象方法檀轨,實現(xiàn)該接口的類必須重寫所有抽象方法
最后
感謝你看到這里脏款,看完有什么的不懂的可以在評論區(qū)問我,覺得文章對你有幫助的話記得給我點個贊裤园,每天都會分享java相關技術文章或行業(yè)資訊撤师,歡迎大家關注和轉發(fā)文章!