文章目錄
繼承
- 繼承實現類的擴展
- 父類也稱作超類、基類、派生類等。
- Java中只有單繼承,沒有像C++那樣的多繼承。多繼承會引起混亂,使得繼承鏈過於複雜,系統難於維護。
- Java中類沒有多繼承,接口有多繼承。
- 子類繼承父類,可以得到父類的全部屬性和方法 (除了父類的構造方法),但不見得可以直接訪問(比如,父類私有的屬性和方法)。
- 如果定義一個類時,沒有調用extends,則它的父類是:java.lang.Object。
package MyPro05;
class Person{
String name;
int height;
public void rest(){
System.out.println("休息...");
}
}
class Student extends Person{
String major;
public Student(){
}
//構造器,繼承了Person的name和height
public Student(String name,int height,String major){
this.name = name;
this.height = height;
this.major = major;
}
public void study(){
System.out.println("學習...");
}
}
public class TestExtends {
public static void main(String[] args) {
Student stu = new Student();
stu.name = "霹靂火秦明";
stu.height = 189;
stu.study();
stu.rest();
}
}
- 查看類的繼承關係,選中類後,IDEA中快捷鍵Ctrl+h,或者右鍵diagram
- instanceof: instanceof是二元運算符,左邊是對象,右邊是類;當對象是右面類或子類所創建對象時,返回true;否則,返回false。是個運算符,像 + - * /那樣用
System.out.println(stu instanceof Student); //true
System.out.println(stu instanceof Person); //true
重寫
- 子類替換父類的行爲。
- “==”: 方法名、形參列表相同。
- “≤”:返回值類型和聲明異常類型,子類小於等於父類。子類方法的返回類型是父類方法返回類型的本身或子類。
- “≥”: 訪問權限,子類大於等於父類。
class Veichle{
void run(){
System.out.println("跑....");
}
void stop(){
System.out.println("靜止不動");
}
Person passager(){
return new Person();
}
int numbers(){ //重寫時不能是double float其他類型
return 1;
}
}
class Horse extends Veichle{
@Override
void run(){
System.out.println("駕。。。駕。。。");
}
@Override
void stop(){
System.out.println("籲。。。。");
}
@Override //返回類型可以爲Person的子類,不能是父類
Student passager() {
return new Student();
}
}
public class TestOverride {
public static void main(String[] args) {
Horse h = new Horse();
h.run();
h.stop();
}
}
- 快捷鍵 Alt + 7查看類的所有字段和方法
Object類
- Object類是所有Java類的根基類,也就意味着所有的Java對象都擁有Object類的屬性和方法。如果在類的聲明中未使用extends關鍵字指明其父類,則默認繼承Object類。
* Class {@code Object} is the root of the class hierarchy.
* Every class has {@code Object} as a superclass. All objects,
* including arrays, implement the methods of this class.
toString方法
- 返回類名和hashCode的字符串。
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
- 重寫toString
@Override
public String toString() {
return "哈哈哈";
}
equals方法
- == 符號,比較雙方是否相同。如果是基本類型則表示值相等,如果是引用類型則表示地址相等即是同一個對象。
- equals 判斷提供定義“對象內容相等”的邏輯
public boolean equals(Object obj) {
return (this == obj);
}
- 自定義equals方法,單擊右鍵generate自動生成
package MyPro05;
class User{
int id;
String name;
String passed;
public User(int id, String name, String passed) {
this.id = id;
this.name = name;
this.passed = passed;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return id == user.id;
}
}
public class TestEquals {
public static void main(String[] args) {
User u1 = new User(1,"玉麒麟","001");
User u2 = new User(1,"盧俊義","002");
System.out.println(u1 == u2); //是否爲同一個對象 false
System.out.println(u1.equals(u2)); //判斷是否相等,根據id判斷,true
}
}
super
- super是直接父類對象的引用。可以通過super來訪問父類中被子類覆蓋的方法或屬性。使用super調用普通方法,語句沒有位置限制,可以在子類中隨便調用。
- 若是構造方法的第一行代碼沒有顯式的調用super(…)或者this(…);那麼Java默認都會調用super(),含義是調用父類的無參數構造方法 。這裏的super()可以省略。構造時從祖宗Object往子孫開始構造,靜態初始化塊也是如此。
//在子類中調用
super.value;
super.method();
- 屬性/方法查找順序:(比如:查找變量h) 1. 查找當前類中有沒有屬性h 。2. 依次上溯每個父類,查看每個父類中是否有h,直到Object 3. 如果沒找到,則出現編譯錯誤。 4. 上面步驟,只要找到h變量,則這個過程終止。
封裝
- 作用:1. 提高代碼的安全性。 2. 提高代碼的複用性。 3. “高內聚”:封裝細節,便於修改內部代碼,提高可維護性。 4. “低耦合”:簡化外部調用,便於調用者使用,便於擴展和協作。
- 訪問控制符 修飾成員變量、方法,類可以default和public,1. private 表示私有,只有自己類能訪問
2. default表示沒有修飾符修飾,只有同一個包的類能訪問
3. protected表示可以被同一個包的類以及其他包中的子類訪問
4. public表示可以被該項目的所有包中的所有類訪問 - 規則 1. 一般使用private訪問權限。 2. 提供相應的get/set方法來訪問相關屬性,這些方法通常是public修飾的,以提供對屬性的賦值與讀取操作(注意:boolean變量的get方法是is開頭)。 3. 一些只用於本類的輔助性方法可以用private修飾,希望其他類調用的方法用public修飾。
- getter setter方法,boolean類型的get是is開頭。使用開發工具快速生成,再修改
class Person2{
private int id;
private int age;
private String name;
private boolean man;
public boolean isMan() {
return man;
}
public void setMan(boolean man) {
this.man = man;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age < 0 || age > 120){
System.out.printf("一般人活不到 %s 歲",age);
}else {
this.age = age;
}
}
public String getName() {
return name;
}
public void setName(String name) {
if(name.length() > 6){
System.out.println("名字太長");
}else{
this.name = name;
}
}
}
public class TestPrivate {
public static void main(String[] args) {
Person2 p = new Person2();
p.setAge(10000);
}
}
多態
-
多態指的是同一個方法調用,由於對象不同可能會有不同的行爲。現實生活中,同一個方法,具體實現會完全不同。
多態的要點: 1. 多態是方法的多態,不是屬性的多態(多態與屬性無關)。 2. 多態的存在要有3個必要條件:繼承,方法重寫,父類引用指向子類對象。 3. 父類引用指向子類對象後,用該父類引用調用子類重寫的方法,此時多態就出現了
package MyPro05;
public class TestMorph {
public static void main(String[] args) {
Animal a = new Animal();
animalShout(a); //調用動物的叫法
Animal d = new Dog();
animalShout(d); //狗的叫法
Animal c = new Cat();
animalShout(c); //貓的叫法
//c沒有抓老鼠的方法,需要強制轉型
Cat ca = (Cat)c; //現在貓可以抓老鼠了
ca.catchMouse();
//將動物外殼的狗轉爲貓,本質上還是狗,抓老鼠會編譯通過,但是實際上還是不會
//Exception in thread "main" java.lang.ClassCastException: MyPro05.Dog cannot be cast to MyPro05.Cat
Cat da = (Cat)d;
da.catchMouse();
}
// 父類引用指向子類對象的方法
static void animalShout(Animal animal){
animal.shout();
}
}
class Animal{
void shout(){
System.out.println(getClass().getName()+"..叫了三聲");
}
}
class Dog extends Animal{
@Override
void shout(){
System.out.println(getClass().getName()+"..汪..汪汪..");
}
}
class Cat extends Animal{
@Override
void shout(){
System.out.println(getClass().getName()+"..喵嗚..喵嗚..");
}
void catchMouse(){
System.out.println("貓抓住了一些老鼠");
}
}
- 轉型 ,父類引用指向子類對象,我們稱這個過程爲向上轉型,屬於自動類型轉換。 向上轉型後的父類引用變量只能調用它編譯類型的方法,不能調用它運行時類型的方法。這時,我們就需要進行類型的強制轉換,我們稱之爲向下轉型
final
- 修飾變量: 被他修飾的變量不可改變。一旦賦了初值,就不能被重新賦值。
final int MAX_SPEED = 120;
- 修飾方法:該方法不可被子類重寫。但是可以被重載!
final void study(){}
- 修飾類: 修飾的類不能被繼承。比如:Math、String等。
final class A {}
數組
- 數組是相同類型數據的有序集合。數組描述的是相同類型的若干個數據,按照一定的先後次序排列組合而成。其中,每一個數據稱作一個元素,每個元素可以通過一個索引(下標)來訪問它們。數組的三個基本特點: 1. 長度是確定的。數組一旦被創建,它的大小就是不可以改變的。 2. 其元素必須是相同類型,不允許出現混合類型。 3. 數組類型可以是任何數據類型,包括基本類型和引用類型。
聲明
- 定義 類型 名稱[] 或類型[] 名稱
int[] intArr;
double[] doubleArr;
Person[] personArr;
Dog[] dogs;
初始化
- 動態,靜態,默認初始化
//默認初始化,和成員變量一致
int[] intArr;
double[] doubleArr;
Person[] personArr;
//動態初始化,下標賦值
int[] intArr2 = new int[10]; //10個元素,默認元素0
//賦值,也可以循環賦值
intArr2[0] = 100;
intArr2[1] = 200;
//循環獲取數組的值
for(int i = 0;i < intArr.length;++i){
System.out.println(intArr[i]);
}
//靜態初始化
int[] intA = {1,2,3,4};
Cat[] cats = {new Cat(),new Cat()};
遍歷
- for循環遍歷,foreach
- for既可以讀取,也可以修改,foreach只能讀取
for(int i = 0;i < intArr.length;++i){
System.out.println(intArr[i]);
}
//foreach方式遍歷
for(int num:intArr){
System.out.println(num);
}
數組的拷貝
- System類裏也包含了一個static void arraycopy(object src,int srcpos,object dest, int destpos,int length)方法,該方法可以將src數組裏的元素值賦給dest數組的元素,其中srcpos指定從src數組的第幾個元素開始賦值,length參數指定將src數組的多少個元素賦給dest數組的元素。
int[] srcArr = {6,7,1,9,5};
int[] dstArr = new int[5];
System.arraycopy(srcArr,1,dstArr,2,3);
- 利用數組的拷貝來插入刪除某個元素
Arrays
- 該類包含用於操作數組的各種方法(排序、查找、填充、打印內容等常見的操作)。 該類還包含一個靜態工廠,可以將數組視爲列表
- 基本數據類型排序可以直接用sort,其他類排序需要實現Comparable接口
import java.util.Arrays;
public class TestArrays {
public static void main(String[] args) {
int[] arrs = {30,100,10,200};
String arrString = Arrays.toString(arrs);
System.out.println(arrString); //[30, 100, 10, 200]
Arrays.sort(arrs); //對數組排序,升序排列,修改數組本身
System.out.println(Arrays.toString(arrs)); //[10, 30, 100, 200]
//[10, 30, 100, 200]
int index = Arrays.binarySearch(arrs,50); //返回元素的索引,不存在返回-1
System.out.println(index);
Arrays.binarySearch(arrs,2,arrs.length,30); //指定範圍搜索
}
}
多維數組
- 多維數組可以看成以數組爲元素的數組
- int[][] a = new int[3][];
import java.util.Arrays;
public class Test2DArray {
public static void main(String[] args) {
int[][] a = new int[3][];
a[0] = new int[]{3,1,2};
a[1] = new int[]{5,4,6,5};
a[2] = new int[]{9,10};
System.out.println(Arrays.toString(a[1])); //[5, 4, 6, 5]
//純靜態初始化
int[][] b = {
{2,3,5},
{100,200,300},
{2000,101,202,303}
};
System.out.println(b[1][2]); //300
}
}
數組存儲表格
- 使用二維數組,一行作爲一個數組
Object[] a1 = {1001,"宋江",48,"呼保義","1098-2-14"};
Object[] a2 = {1002,"盧俊義",39,"玉麒麟","1098-10-10"};
Object[] a3 = {1003,"吳用",40,"智多星","1098-5-5"};
Object[][] emps = new Object[3][];
emps[0] = a1;
emps[1] = a2;
emps[2] = a3;
System.out.println(Arrays.toString(emps[0]));
System.out.println(Arrays.toString(emps[1]));
System.out.println(Arrays.toString(emps[2]));
冒泡排序
- 冒泡比較,大的往後放
import java.util.Arrays;
public class TestBubbleSort {
public static void main(String[] args) {
int[] arr = {3,1,2,4,6,2,9,7,5};
BubbleSort(arr);
System.out.println("-----------");
System.out.println(Arrays.toString(arr));
}
//冒泡排序的函數,修改數組本身
static void BubbleSort(int[] arr){
int temp = 0;
boolean flag ; //記錄是否發生了交換,如果不交換表示已經排好序了
for(int i =0;i < arr.length;i++) { //i爲已排好序的個數
flag = false;
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = true;
}
System.out.println(Arrays.toString(arr));
}
if (!flag) {
break;
}
System.out.println("***********");
}
}
}
二分法查找
- 對排好序的數組查找
import java.util.Arrays;
public class TestBinarySearch {
public static void main(String[] args) {
int[] arr = {300,100,200,4000,600,22,912,72,59};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
int index = BinarySearch(arr,100);
System.out.println(index);
}
static int BinarySearch(int[] arr,int value){
int low = 0;
int high = arr.length - 1;
int mid;
while (low <= high){
mid = (low + high) / 2;
if(arr[mid] == value){
return mid;
}else if(arr[mid] > value){
high -= 1;
}else if(arr[mid] < value){
low +=1;
}
}
return -1;
}
}
抽象方法和抽象類
- 使用abstract修飾的方法,沒有方法體,只有聲明。子類必須要給抽象方法提供具體的實現。
- 抽象類裏可以有具體方法,子類可以重寫也可以不重寫
- 字段不能用abstract修飾
- 抽象類不能用來創建對象,只能被繼承
- 抽象類可以包含屬性、方法、構造方法。但是構造方法不能用來new實例,只能用來被子類調用。
package MyPro06;
//抽象類,沒有實現的方法子類必須實現
abstract class Animal{
int legs;
double weight;
public void shout(){
System.out.println("哈哈哈哈");
}
abstract void run();
}
class Dog extends Animal{
@Override
void run() {
System.out.println("四條腿跑");
}
public void eat(){
System.out.println("喫骨頭");
}
}
public class TestAbstract {
public static void main(String[] args) {
Dog d = new Dog();
d.run();
d.eat();
}
}
接口
接口使用
-
比抽象類更加抽象,接口不提供任何實現,接口中所有方法都是抽象方法
-
定義接口的詳細說明:
- 訪問修飾符:只能是public或默認。
- 接口名:和類名採用相同命名機制。
- extends:接口可以多繼承。
- 常量:接口中的屬性只能是常量,總是:public static final 修飾。不寫也是。
- 方法:接口中的方法只能是:public abstract。 省略的話,也是public abstract。
-
要點
-
子類通過implements來實現接口中的規範。
-
接口不能創建實例,但是可用於聲明引用變量類型。
-
一個類實現了接口,必須實現接口中所有的方法,並且這些方法只能是public的。
-
JDK1.7之前,接口中只能包含靜態常量、抽象方法,不能有普通屬性、構造方法、普通方法。
-
JDK1.8後,接口中包含普通的靜態方法
-
package MyPro06;
interface Haohan{
int NUMS = 108; //總是public static final修飾
void qiYi();
void tiTianXingDao();
static void sing(){
System.out.println("大河向東流,七天的星星參北斗");
}
}
class TianGang implements Haohan{
@Override
public void qiYi() {
System.out.println("三打祝家莊");
}
@Override
public void tiTianXingDao() {
System.out.println("劫富濟貧");
}
}
public class TestInterface {
public static void main(String[] args) {
System.out.println(Haohan.NUMS); //接口的常量可以直接使用
Haohan.sing();
TianGang t = new TianGang();
t.qiYi();
t.tiTianXingDao();
}
}
接口的多重繼承
- 接口可以多繼承extends,類只能單繼承extends,但可以實現多個接口implents
interface A{
void testa();
}
interface B{
void testb();
}
interface C extends A,B{
void testc();
}
class Test implements A,B,C{
@Override
public void testa() {
}
@Override
public void testb() {
}
@Override
public void testc() {
}
}
內部類
概念
-
我們把一個類放在另一個類的內部定義,稱爲內部類(innerclasses)。 內部類可以使用public、default、protected 、private以及static修飾。而外部頂級類(我們以前接觸的類)只能使用public和default修飾。
-
內部類的作用:
1. 內部類提供了更好的封裝。只能讓外部類直接訪問,不允許同一個包中的其他類直接訪問。 2. 內部類可以直接訪問外部類的私有屬性,內部類被當成其外部類的成員。 但外部類不能訪問內部類的內部屬性。 3. 接口只是解決了多重繼承的部分問題,而內部類使得多重繼承的解決方案變得更加完整。
-
內部類的使用場合:
1. 由於內部類提供了更好的封裝特性,並且可以很方便的訪問外部類的屬性。所以,在只爲外部類提供服務的情況下可以優先考慮使用內部類。 2. 使用內部類間接實現多繼承:每個內部類都能獨立地繼承一個類或者實現某些接口,所以無論外部類是否已經繼承了某個類或者實現了某些接口,對於內部類沒有任何影響。
-
分類:成員內部類(非靜態內部類、靜態內部類)、匿名內部類、局部內部類
成員內部類
- 成員內部類(可以使用private、default、protected、public任意進行修飾。 類文件:外部類$內部類.class)。非靜態內部類看作外部類的成員,靜態內部類看作靜態成員
非靜態內部類
- 外部類裏使用非靜態內部類和平時使用其他類沒什麼不同
- 非靜態內部類必須寄存在一個外部類對象裏。因此,如果有一個非靜態內部類對象那麼一定存在對應的外部類對象。非靜態內部類對象單獨屬於外部類的某個對象。
- 非靜態內部類可以直接訪問外部類的成員,但是外部類不能直接訪問非靜態內部類成員。
- 非靜態內部類不能有靜態方法、靜態屬性和靜態初始化塊。
- 外部類的靜態方法、靜態代碼塊不能訪問非靜態內部類,包括不能使用非靜態內部類定義變量、創建實例
- 內部類的類型爲
Outer類.Inner類
,如果有多層就從外向裏寫,創建時使用外部類對象.new 內部類
public class TestInnerClass {
public static void main(String[] args) {
//創建非靜態內部類對象,必須依託外部類對象
Outer.Inner inner = new Outer().new Inner();
inner.show();
// //再創建一個,外部類對象的new方法
// Outer outer = new Outer();
// Outer.Inner inner1 = outer.new Inner();
// inner1.show();
//內部類的內部類
System.out.println("----");
Outer.Inner.Innest innest = inner.new Innest();
innest.speak();
}
}
class Outer{
int id = 100;
String name = "大刀關勝";
void jiaoFei(){}
class Inner{
int id = 101;
String name = "豹子頭林沖";
void show(){
int id = 102;
System.out.println("方法的變量:"+id); //102
System.out.println("內部類的變量:"+this.id); //101
System.out.println("外部類的變量:"+Outer.this.id); //100
}
class Innest{
int id = 103;
void speak(){
int id = 104;
System.out.println("方法的變量:"+id); //104
System.out.println("內部類的變量:"+this.id); //103
System.out.println("第一外部類的變量:"+Outer.Inner.this.id);//101
System.out.println("最外層外部類的變量:"+Outer.this.id); //100
}
}
}
}
靜態內部類
-
當一個靜態內部類對象存在,並不一定存在對應的外部類對象。 因此,靜態內部類的實例方法不能直接訪問外部類的實例方法。
-
靜態內部類看做外部類的一個靜態成員。因此,外部類的方法中可以通過:“靜態內部類.名字”的方式訪問靜態內部類的靜態成員,通過 new 靜態內部類()訪問靜態內部類的實例。
public class TestStaticInnerClass {
public static void main(String[] args) {
Outer2.Inner2 inner2 = new Outer2.Inner2(); //靜態內部類創建
inner2.show();
//
Outer2 outer2 = new Outer2();
outer2.speak();
}
}
class Outer2{
int id = 201;
static String name = "a";
//非靜態方法
void speak(){
//實例化調用內部類
Inner2 i2 = new Inner2();
i2.show();
//靜態方法
Inner2.speak();
}
//靜態內部類
static class Inner2{
int id = 202;
void show(){
System.out.println("內部類成員:"+this.id); //202
//System.out.println("外部類成員"+Outer2.this.id); 不能這樣做,不能訪問外部類的非靜態成員
System.out.println("外部類的靜態成員:"+Outer2.name);
}
static void speak(){
System.out.println("靜態內部類的靜態方法");
}
}
}
匿名內部類
- 適合那種只需要使用一次的類。比如:鍵盤監聽操作等
new 父類構造器(實參類表) \實現接口 () {
//匿名內部類類體!
}
public class TestAnornamousInnerClass {
static void test(AA a){
System.out.println("****");
a.aa();
}
public static void main(String[] args) {
//傳遞內部類
test(new AA(){
public void aa(){
System.out.println("aaa");
}
});
}
}
interface AA{
void aa();
}
局部內部類
- 定義在方法內部的,作用域只限於本方法,稱爲局部內部類
- 局部內部類的的使用主要是用來解決比較複雜的問題,想創建一個類來輔助我們的解決方案,到那時又不希望這個類是公共可用的,所以就產生了局部內部類。局部內部類和成員內部類一樣被編譯,只是它的作用域發生了改變,它只能在該方法中被使用,出了該方法就會失效。
- 較少使用
public class Test2 {
public void show() {
//作用域僅限於該方法
class Inner {
public void fun() {
System.out.println("helloworld");
}
}
new Inner().fun();
}
public static void main(String[] args) {
new Test2().show();
}
}
String類
- 本質上是字符型的數組
- String類又稱作不可變字符序列。String位於java.lang包中,Java程序默認導入java.lang包下的所有類
- 字符串比較相等使用equals方法
String s = "abc123";
String s1 = new String("abc123");
String s2 = "abc"+123; //abc123
System.out.println(s == s1); //比較是不是同一個對象,false
System.out.println(s == s2); //true
System.out.println(s.equals(s1));//比較是否相等,true
- 下載java的API文檔。鏈接:https://pan.baidu.com/s/1hNBIMaSu2CkkK2n3p5-6Mg
提取碼:8csd - 常用的方法:charAt,equals,equalsIgnoreCase,indexOf,lastIndexOf,length,replace,startsWith,endsWith,substring,toLowerCase,toUpperCase,trim