Java中的包、抽象類、接口詳解(最新整理)
包
包 (package) 是組織類的一種方式, 使用包的主要目的是保證類的唯一性. 例如 , 你在代碼中寫了一個(gè) Test 類 . 然后你的同事也可能寫一個(gè) Test 類 . 如果出現(xiàn)兩個(gè)同名的類 , 就會(huì)沖突 , 導(dǎo)致代碼不能編譯通過(guò).
導(dǎo)入包
Java 中已經(jīng)提供了很多現(xiàn)成的類供我們使用 . 例如
public class Test { public static void main(String[] args) { java.util.Date date = new java.util.Date(); // 得到一個(gè)毫秒級(jí)別的時(shí)間戳 System.out.println(date.getTime()); } }
可以使用 java.util.Date 這種方式引入 java.util 這個(gè)包中的 Date 類 . 但是這種寫法比較麻煩一些 , 可以使用 import 語(yǔ)句導(dǎo)入包 . 如果需要使用 java.util 中的其他類 , 可以使用 import java.util.* 但是我們更建議顯式的指定要導(dǎo)入的類名 . 否則還是容易出現(xiàn)沖突的情況
注意事項(xiàng) : import 和 C++ 的 #include 差別很大 . C++ 必須 #include 來(lái)引入其他文件內(nèi)容 , 但是 Java 不需要 . import 只是為了寫代碼的時(shí)候更方便 . import 更類似于 C++ 的 namespace 和 using
靜態(tài)導(dǎo)入
使用 import static 可以導(dǎo)入包中的靜態(tài)的方法和字段。
import static java.lang.System.*; public class Test { public static void main(String[] args) { out.println("hello"); } }
使用這種方式可以更方便的寫一些代碼, 例如
import static java.lang.Math.*; public class Test { public static void main(String[] args) { double x = 30; double y = 40; // 靜態(tài)導(dǎo)入的方式寫起來(lái)更方便一些. // double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); double result = sqrt(pow(x, 2) + pow(y, 2)); System.out.println(result); } }
將類放入包
基礎(chǔ)規(guī)則
在文件的最上方加上一個(gè) package 語(yǔ)句指定該代碼在哪個(gè)包中 . 包名需要盡量指定成唯一的名字 , 通常會(huì)用公司的域名的顛倒形式 ( 例如 com.bit.demo1 ). 包名要和代碼路徑相匹配 . 例如創(chuàng)建 com.bit.demo1 的包 , 那么會(huì)存在一個(gè)對(duì)應(yīng)的路徑 com/bit/demo1 來(lái)存儲(chǔ)代碼. 如果一個(gè)類沒有 package 語(yǔ)句 , 則該類被放到一個(gè)默認(rèn)包中 .
常見的系統(tǒng)包
1. java.lang: 系統(tǒng)常用基礎(chǔ)類 (String 、 Object), 此包從 JDK1.1 后自動(dòng)導(dǎo)入。
2. java.lang.reflect:java 反射編程包 ;
3. java.net: 進(jìn)行網(wǎng)絡(luò)編程開發(fā)包。
4. java.sql: 進(jìn)行數(shù)據(jù)庫(kù)開發(fā)的支持包。
5. java.util: 是 java 提供的工具程序包, ( 集合類等 )。
6. java.io:I/O 編程開發(fā)包。
抽象類
語(yǔ)法規(guī)則
像這種沒有實(shí)際工作的方法, 我們可以把它設(shè)計(jì)成一個(gè) 抽象方法 (abstract method) , 包含抽象方法的類我們稱為 抽象類(abstract class)。
abstract class Shape { abstract public void draw(); }
在 draw 方法前加上 abstract 關(guān)鍵字 , 表示這是一個(gè)抽象方法 . 同時(shí)抽象方法沒有方法體 ( 沒有 { }, 不能執(zhí)行具體代碼). 對(duì)于包含抽象方法的類 , 必須加上 abstract 關(guān)鍵字表示這是一個(gè)抽象類 .
總結(jié)
1.抽象類是被abstract修飾的
2.被abstract修飾的方法稱為抽象方法,該方法可以沒有具體的實(shí)現(xiàn)。3.當(dāng)一個(gè)類中含有抽象方法的時(shí)候,該類必須使用abstract修飾
4.抽象類當(dāng)中可以有和普通類一樣的成員變量和一樣的成員方法
5.抽象類是不可以被實(shí)例化的。
6.抽象類既然不能實(shí)例化對(duì)象那么要抽象類干什么???就是為了被繼承。
7.當(dāng)一個(gè)普通的類繼承了這個(gè)抽象類之后,這個(gè)普通類一定要重寫這個(gè)抽象類當(dāng)中所有的抽象方法。8.final和abstract是不同同時(shí)存在的,抽象方法不能被private和static修飾!
9.當(dāng)一個(gè)抽象類A不想被一個(gè)普通類B繼承,此時(shí)可以把B這個(gè)類變成抽象類,那么再當(dāng)一個(gè)普通類C繼承這個(gè)抽象類B之后,C要重寫B(tài)和A里面所有的抽象方法。
注意事項(xiàng):
1) 抽象類不能直接實(shí)例化
Shape shape = new Shape(); // 編譯出錯(cuò) Error:(30, 23) java: Shape是抽象的; 無(wú)法實(shí)例化
2) 抽象方法不能是 private 的
abstract class Shape { abstract private void draw(); } // 編譯出錯(cuò) Error:(4, 27) java: 非法的修飾符組合: abstract和private
3) 抽象類中可以包含其他的非抽象方法 , 也可以包含字段 . 這個(gè)非抽象方法和普通方法的規(guī)則都是一樣的 , 可以被重寫 , 也可以被子類直接調(diào)用
abstract class Shape { abstract public void draw(); void func() { System.out.println("func"); } } class Rect extends Shape { ... } public class Test { public static void main(String[] args) { Shape shape = new Rect(); shape.func(); } } // 執(zhí)行結(jié)果 func
4)抽象類不一定有抽象方法,但有抽象方法的類一定是抽象類。
5)抽象類中可以有構(gòu)造方法,供子類創(chuàng)建對(duì)象時(shí),初始化父類的成員變量。
抽象類的作用
抽象類存在的最大意義就是為了被繼承 . 抽象類本身不能被實(shí)例化 , 要想使用 , 只能創(chuàng)建該抽象類的子類 . 然后讓子類重寫抽象類中的抽象方法 .
接口
接口是抽象類的更進(jìn)一步 . 抽象類中還可以包含非抽象方法 , 和字段 . 而接口中包含的方法都是抽象方法 , 字段只能包含靜態(tài)常量。
語(yǔ)法規(guī)則
interface IShape { void draw(); } class Cycle implements IShape { @Override public void draw() { System.out.println("○"); } } public class Test { public static void main(String[] args) { IShape shape = new Rect(); shape.draw(); } }
1.使用 interface 定義一個(gè)接口
2.接口中的方法一定是抽象方法 , 因此可以省略 abstract
3.接口中的方法一定是 public, 因此可以省略 public
4.Cycle 使用 implements 繼承接口 . 此時(shí)表達(dá)的含義不再是 " 擴(kuò)展 ", 而是 " 實(shí)現(xiàn) "
5.在調(diào)用的時(shí)候同樣可以創(chuàng)建一個(gè)接口的引用 , 對(duì)應(yīng)到一個(gè)子類的實(shí)例 .
6.接口不能單獨(dú)被實(shí)例化
接口中只能包含抽象方法. 對(duì)于字段來(lái)說(shuō), 接口中只能包含靜態(tài)常量(final static).
interface IShape { void draw(); public static final int num = 10; }
其中的 public, static, final 的關(guān)鍵字都可以省略. 省略后的 num 仍然表示 public 的靜態(tài)常量。
總結(jié)
1.使用interface來(lái)定義一個(gè)接口
⒉.接口當(dāng)中的成員變量默認(rèn)是public static final的,一般情況下我們不寫3.接口當(dāng)中的成員方法默認(rèn)是public abstact ,一般情況下我們不寫
4.接口當(dāng)中不可以有普通的方法。
5.Java8開始允許在接口當(dāng)中定義一個(gè)default方法,可以有具體的實(shí)現(xiàn)的6.接口當(dāng)中的方法如果是static修飾的方法那么是可以有具體的實(shí)現(xiàn)的
7.接口不能通過(guò)new關(guān)鍵字進(jìn)行實(shí)例化。
8.類和接口之間可以通過(guò)關(guān)鍵字implements來(lái)實(shí)現(xiàn)接口。9.接口也可以發(fā)生向上轉(zhuǎn)型和動(dòng)態(tài)綁定的。
10.當(dāng)一個(gè)類實(shí)現(xiàn)接口當(dāng)中的方法之后,當(dāng)前類當(dāng)中的方法不能不加public11.接口當(dāng)中不能有構(gòu)造方法和代碼塊。
12.一個(gè)接口也會(huì)產(chǎn)生獨(dú)立的字節(jié)碼文件。
實(shí)現(xiàn)多個(gè)接口
有的時(shí)候我們需要讓一個(gè)類同時(shí)繼承自多個(gè)父類. 這件事情在有些編程語(yǔ)言通過(guò) 多繼承 的方式來(lái)實(shí)現(xiàn)的。然而 Java 中只支持單繼承, 一個(gè)類只能 extends 一個(gè)父類. 但是可以同時(shí)實(shí)現(xiàn)多個(gè)接口, 也能達(dá)到多繼承類似的效果.
現(xiàn)在我們通過(guò)類來(lái)表示一組動(dòng)物.
class Animal { protected String name; public Animal(String name) { this.name = name; } }
另外我們?cè)偬峁┮唤M接口 , 分別表示 " 會(huì)飛的 ", " 會(huì)跑的 ", " 會(huì)游泳的”。
interface IFlying { void fly(); } interface IRunning { void run(); } interface ISwimming { void swim(); }
接下來(lái)我們創(chuàng)建幾個(gè)具體的動(dòng)物 貓 , 是會(huì)跑的 .
class Cat extends Animal implements IRunning { public Cat(String name) { super(name); } @Override public void run() { System.out.println(this.name + "正在用四條腿跑"); } }
魚 , 是會(huì)游的。
class Fish extends Animal implements ISwimming { public Fish(String name) { super(name); } @Override public void swim() { System.out.println(this.name + "正在用尾巴游泳"); } }
青蛙 , 既能跑 , 又能游 ( 兩棲動(dòng)物 )。
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 + "正在蹬腿游泳"); } }
還有一種神奇的動(dòng)物 , 水陸空三棲 , 叫做 " 鴨子 "。
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 + "正在漂在水上"); } }
上面的代碼展示了 Java 面向?qū)ο缶幊讨凶畛R姷挠梅? 一個(gè)類繼承一個(gè)父類, 同時(shí)實(shí)現(xiàn)多種接口.
繼承表達(dá)的含義是 is - a 語(yǔ)義, 而接口表達(dá)的含義是 具有 xxx 特性 .
貓是一種動(dòng)物, 具有會(huì)跑的特性.
青蛙也是一種動(dòng)物, 既能跑, 也能游泳
鴨子也是一種動(dòng)物, 既能跑, 也能游, 還能飛
接口間的繼承
接口可以繼承一個(gè)接口, 達(dá)到復(fù)用的效果. 使用 extends 關(guān)鍵字.
interface IRunning { void run(); } interface ISwimming { void swim(); } // 兩棲的動(dòng)物, 既能跑, 也能游 interface IAmphibious extends IRunning, ISwimming { } class Frog implements IAmphibious { ... }
通過(guò)接口繼承創(chuàng)建一個(gè)新的接口 IAmphibious 表示 " 兩棲的 ". 此時(shí)實(shí)現(xiàn)接口創(chuàng)建的 Frog 類 , 就繼續(xù)要實(shí)現(xiàn) run 方法 , 也需要實(shí)現(xiàn) swim 方法 . 接口使用實(shí)例 給對(duì)象數(shù)組排序
class Student{ private String name; private int score; public Student(String name, int score) { this.name = name; this.score = score; } @Override public String toString() { return "[" + this.name + ":" + this.score + "]"; } } public class test { public static void main(String[] args) { Student[] students = new Student[] { new Student("張三", 95), new Student("李四", 96), new Student("王五", 97), new Student("趙六", 92), }; Arrays.sort(students); System.out.println(Arrays.toString(students)); } }
運(yùn)行會(huì)發(fā)現(xiàn),拋異常了,原因是我們是對(duì)學(xué)生對(duì)象進(jìn)行排序的,而非像整數(shù)這樣顯而易見能比大小的,因此我們需要實(shí)現(xiàn)Comparable接口,并實(shí)現(xiàn)其compareTo()方法。
(法一)實(shí)現(xiàn)Comparable接口的compareTo()方法
class Student implements Comparable<Student>{ private String name; private int score; public Student(String name, int score) { this.name = name; this.score = score; } @Override public String toString() { return "[" + this.name + ":" + this.score + "]"; } // @Override // public int compareTo(Object o) { // Student s=(Student)o; // return this.score-s.score; // } @Override public int compareTo(Student o) { return this.score-o.score; } } public class test { public static void main(String[] args) { Student[] students = new Student[] { new Student("張三", 95), new Student("李四", 96), new Student("王五", 97), new Student("趙六", 92), }; Arrays.sort(students); System.out.println(Arrays.toString(students)); } }
運(yùn)行結(jié)果
(法二)實(shí)現(xiàn)Comparator比較器的compare()方法
class Student{ public String name; public int score; public Student(String name, int score) { this.name = name; this.score = score; } @Override public String toString() { return "[" + this.name + ":" + this.score + "]"; } } class AgeComparator implements Comparator<Student>{ @Override public int compare(Student o1, Student o2) { return o1.score-o2.score; } } class NameComparator implements Comparator<Student>{ @Override public int compare(Student o1, Student o2) { return o1.name.compareTo(o2.name); } } public class test { public static void main(String[] args) { Student student1 = new Student("zhangsan",10); Student student2 = new Student("lisi",15); AgeComparator ageComparator = new AgeComparator(); System.out.println(ageComparator.compare(student1, student2)); NameComparator nameComparator = new NameComparator(); System.out.println(nameComparator.compare(student1,student2)); } }
運(yùn)行結(jié)果
Clonable接口和深拷貝
Java 中內(nèi)置了一些很有用的接口, Clonable 就是其中之一.
Object 類中存在一個(gè) clone 方法, 調(diào)用這個(gè)方法可以創(chuàng)建一個(gè)對(duì)象的 "拷貝". 但是要想合法調(diào)用 clone 方法, 必須要先實(shí)現(xiàn) Clonable 接口, 否則就會(huì)拋出 CloneNotSupportedException 異常.
class Money{ public double money = 19.9; } class Person implements Cloneable{ public int age; public Money m; public Person(int age) { this.age = age; this.m = new Money(); } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Person{" + " age=" + age + '}'; } } public class Test2 { public static void main(String[] args) throws CloneNotSupportedException { Person person1 = new Person(10); Person person2 = (Person)person1.clone(); System.out.println(person1.m.money); System.out.println(person2.m.money); System.out.println("=========================="); person2.m.money = 99.99; System.out.println(person1.m.money); System.out.println(person2.m.money); } }
運(yùn)行結(jié)果
與我們預(yù)期的19.9 99.99不符,顯然是因?yàn)檫@里是淺拷貝,因此我們需要對(duì)m實(shí)現(xiàn)深拷貝。
原因如下圖:
實(shí)現(xiàn)深拷貝后
class Money implements Cloneable{ public double money = 19.9; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Person implements Cloneable{ public int age; public Money m; public Person(int age) { this.age = age; this.m = new Money(); } @Override protected Object clone() throws CloneNotSupportedException { Person tmp = (Person) super.clone(); tmp.m = (Money) this.m.clone(); return tmp; } @Override public String toString() { return "Person{" + " age=" + age + '}'; } } public class Test2 { public static void main(String[] args) throws CloneNotSupportedException { Person person1 = new Person(10); Person person2 = (Person)person1.clone(); System.out.println(person1.m.money); System.out.println(person2.m.money); System.out.println("=========================="); person2.m.money = 99.99; System.out.println(person1.m.money); System.out.println(person2.m.money); } }
運(yùn)行結(jié)果:
實(shí)現(xiàn)方法如下圖:
抽象類和接口的區(qū)別
核心區(qū)別: 抽象類中可以包含普通方法和普通字段, 這樣的普通方法和字段可以被子類直接使用(不必重寫), 而接口中不能包含普通方法, 子類必須重寫所有的抽象方法.
到此這篇關(guān)于Java中的包、抽象類、接口詳解的文章就介紹到這了,更多相關(guān)Java包 抽象類 接口內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解SpringBoot讀取resource目錄下properties文件的常見方式
這篇文章主要介紹了SpringBoot讀取resource目錄下properties文件的常見方式,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02Spring事務(wù)傳播屬性和隔離級(jí)別詳細(xì)介紹
這篇文章主要介紹了Spring事務(wù)傳播屬性和隔離級(jí)別詳細(xì)介紹,同時(shí)涉及傳播行為介紹,超時(shí)設(shè)置等相關(guān)內(nèi)容,需要的朋友可以參考下。2017-09-09java并發(fā)編程之深入理解Synchronized的使用
文詳細(xì)講述了線程、進(jìn)程的關(guān)系及在操作系統(tǒng)中的表現(xiàn),這是多線程學(xué)習(xí)必須了解的基礎(chǔ)。本文將接著講一下Java線程同步中的一個(gè)重要的概念synchronized,希望能夠給你有所幫助2021-06-06Spring Boot + Vue 前后端分離開發(fā)之前端網(wǎng)絡(luò)請(qǐng)求封裝與配置
這篇文章主要介紹了Spring Boot + Vue 前后端分離開發(fā)之前端網(wǎng)絡(luò)請(qǐng)求封裝與配置方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-05-05Spring Data Envers支持有條件變動(dòng)紀(jì)錄的保存和查詢的方法
通過(guò)spring-data-envers可以很容易的實(shí)現(xiàn)數(shù)據(jù)變動(dòng)紀(jì)錄的保存和查詢,本文介紹支持有條件變動(dòng)紀(jì)錄的保存和查詢的方法,通過(guò)spring-data-envers很容易的實(shí)現(xiàn)變動(dòng)紀(jì)錄的保存和查詢,只需要增加幾個(gè)注解就可以,感興趣的朋友跟隨小編一起看看吧2023-10-10