272,包基本介紹
-
包的三大作用
1,區分相同的類 2,當類很多時,可以很好的管理類 3,控制訪問範圍
包基本用法
package com.hspedu; 說明: 1,package 關鍵字,表示打包 2,com.hspedu,表示包名
-
包的本質分析(原理)
包的本質 實際上就是建立不同的資料夾/目錄 來儲存類檔案
不同包下的Dog類
import com.xiaoqiang.Dog;
public class test1 {
public static void main(String[] args) {
Dog dog = new Dog();//不匯入包的話,也可以 com.xiaoqiang.Dog dog = new com.xiaoqiang.Dog();
System.out.println(dog);
com.xiaoming.Dog dog1 = new com.xiaoming.Dog();//不能再匯入包,否則上面的dog會分不清
System.out.println(dog1);
}
}
執行結果:
-
包命名
命名規則:只能包含數字,字母,下劃線,小圓點.,但不能用數字開頭,不能是關鍵字或保留字
命名規範:一般是小寫字母+小圓點。比如:com.公司名.專案名.業務模組名 舉例:com.sina.crm.user
-
包的使用細節:
1,package 的作用是宣告當前類所在的包,需要放在類的最上面,一個類中最多隻有一句package。比如 package com.hspedu.pkg
2,import指令 位置放在 package 的下面,在類定義前面,可以有多句且沒有順序要求。
3,我們引入一個包的主要目的是要使用該包下的類 import java.util.Scanner 表示只會引入java.util 包下的Scanner;import java.util.* 表示將java.util 包下的所有類都引入(匯入)
建議:我們需要使用到哪個類,就匯入哪個類即可,不建議使用 * 匯入
278,訪問修飾符
280,封裝介紹
對電視機的操作就是典型封裝。
類中的 set, get 方法用 快捷鍵 fn + alt + insert (筆記本)生成
286,繼承原理圖
父類 Student 程式碼
package com.extend_.improve;
public class Student { //是Pupil的父類
//共有的屬性
public String name;
public int age;
private double score;//私有需要透過set來訪問設定
//共有的方法
public void setScore(double score)
{
this.score = score;
}
public void showInfo()
{
System.out.println("學生名 " + name + " 年齡 " + age + " 成績 " + score);
}
}
子類 Pupil 程式碼
package com.extend_.improve;
public class Pupil extends Student{
public void testing()
{
System.out.println("小學生 " + name + " 正在考小學數學");
}
}
主類 Extends 程式碼
package com.extend_.improve;//匯入包就能用包下的所有類了
public class Extends {
public static void main(String[] args)
{
com.extend_.improve.Pupil pupil = new Pupil();
pupil.name = "銀角大王";
pupil.age = 11;
pupil.testing();//pupil類自己的方法
pupil.setScore(60);//呼叫父類方法
pupil.showInfo();//呼叫父類方法
}
}
執行結果:
288,繼承使用細節
1,子類繼承了所有的屬性和方法,非私有的屬性和方法可以在子類直接訪問,但是私有屬性和方法不能在子類直接訪問,要透過父類提供公共的方法去訪問
父類程式碼
package com.extend_.improve;
public class Student { //是Pupil的父類
//4個屬性
public int n1 = 1;
protected int n2 = 2;
int n3 = 3;
private int n4 = 4;
public Student()//無參構造器
{
System.out.println("Student()....");
}
//父類提供一個public的方法,返回了n4
public int getN4()
{
return n4;
}
public void test1()
{
System.out.println("test1");
}
protected void test2()
{
System.out.println("test2");
}
void test3()
{
System.out.println("test3");
}
private void test4()
{
System.out.println("test4");
}
public void callTest4()
{
test4();
}
}
子類程式碼
package com.extend_.improve;
public class Pupil extends Student{
public Pupil()//構造器
{
System.out.println("Pupil()....");
}
public void sayOk()//子類方法
{
//非私有的屬性和方法可以在子類直接訪問
//但是私有屬性和方法不能在子類直接訪問
System.out.println(n1 + " " + n2 + " " + n3);
test1();
test2();
test3();
//要透過父類提供的公共方法去訪問
System.out.println("n4 = " + getN4());
callTest4();
}
}
主類程式碼
package com.extend_.improve;//匯入包就能用包下的所有類了
public class Extends {
public static void main(String[] args)
{
Pupil pupil = new Pupil();
pupil.sayOk();
}
}
執行結果:
2,子類必須呼叫父類的構造器,完成父類的初始化
3,當建立子類物件時,不管使用子類的哪個構造器,預設情況下總會去呼叫父類的無參構造器;如果父類沒有提供無參構造器,則必須在子類的構造器中用 super去指定使用父類的哪個構造器完成對父類的初始化工作,否則,編譯不會透過。
以下是父類沒有提供無參構造器的程式碼
父類程式碼
package com.extend_.improve;
public class Student { //是Pupil的父類
//4個屬性
public int n1 = 1;
protected int n2 = 2;
int n3 = 3;
private int n4 = 4;
// public Student()//無參構造器
// {
// System.out.println("父類Student()構造器被呼叫....");
// }
public Student(int num1, int num2)
{
System.out.println("父類Student(int num1, int num2)構造器被呼叫....");
}
}
子類程式碼
package com.extend_.improve;
public class Pupil extends Student{
public Pupil()//構造器
{
super(10,10);
System.out.println("子類Pupil()構造器被呼叫....");
}
public Pupil(int num1)
{
super(10,10);
System.out.println("子類Pupil(int num)構造器被呼叫....");
}
}
主類程式碼
package com.extend_.improve;//匯入包就能用包下的所有類了
public class Extends {
public static void main(String[] args)
{
System.out.println("=====第一個物件=====");
Pupil pupil1 = new Pupil();
System.out.println("=====第二個物件=====");
Pupil pupil2 = new Pupil(1);
}
}
執行結果
4,如果希望指定去呼叫父類的某個構造器,則顯示的呼叫一下:super(引數列表)
5,super在使用時,需要放在構造器第一行
6,super() 和 this() 都只能放在構造器第一行,因此這兩個方法不能共存在一個構造器。super() 是呼叫父類構造器的,this()是呼叫本類構造器的
7,java 所有類都是 Object 類的子類,Object 類是所有類的基類。按 ctrl + h 可以看到類的繼承關係。
8,父類構造器的呼叫不限於直接父類!將一直往上追溯直到 Object 類(頂級父類)
9,子類最多隻能繼承一個父類(指直接繼承),即 java 中是單繼承機制。
10,不能濫用繼承,子類和父類之間必須滿足合理的關係
293,繼承本質詳解
如果要訪問 son.age,要按照查詢關係來返回資訊
(1),首先看子類是否有該屬性
(2),如果子類有這個屬性,並且可以訪問,則返回資訊
(3),如果子類沒有這個屬性,就看父類有沒有這個屬性(如果父類有該屬性,並且可以訪問,就返回資訊)
(4),如果父類沒有就按照(3)的規則,繼續找上級父類,直到 Object
297,super 基本語法
298,super 使用細節
如果沒有重名,使用super,this,直接訪問,這3種方法都能訪問到父類的非私有的屬性和方法。
this 查詢的規則
(1),先找本類,如果有,則呼叫
(2),如果沒有,則找父類(如果有,並可以呼叫,則呼叫)
(3),如果父類沒有,則繼續找父類的父類,整個規則,就是一樣的,直到 Object 類
提示:如果查詢屬性的過程中,找到了,但是不是訪問,則保錯, cannot access
如果查詢方法的過程中,沒有找到,則提示方法不存在
300,super使用細節3
1,super 和 this 的比較
301,方法重寫介紹
父類 Animal 程式碼
package com.extend_.improve;
public class Animal {
public void cry()
{
System.out.println("動物叫喚....");
}
}
子類 Dog 程式碼
package com.extend_.improve;
public class Dog extends Animal{
public void cry()//Dog 類的 cry 方法和 Animal 的 cry 定義形式一樣(名稱,返回型別,引數),這時我們就說 Dog 的 cry 方法,重寫了 Animal 的 cry 方法
{
System.out.println("小狗叫喚....");
}
}
主類 程式碼
package com.extend_.improve;//匯入包就能用包下的所有類了
public class Extends {
public static void main(String[] args)
{
Dog dog = new Dog();
dog.cry();
}
}
執行結果:
302,方法重寫細節
303,重寫課題練習1
-
方法的重寫和過載做一個比較
305,養寵物引出多型
有兩個父類:Food類 和 Animal類。其中 Food類的子類是Bone類和Fish類,Animal類的子類是Dog類和Cat類。Master主人類的方法是會用到food類和Animal類的子類,主類是Poly類。
Food類程式碼
package com.extend_.improve;
public class Food {
private String name;//私有屬性,類外的話需要透過get方法來訪問
public Food(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Bone類程式碼
package com.extend_.improve;
public class Bone extends Food{
public Bone(String name) {
super(name);
}
}
fish類程式碼
package com.extend_.improve;
public class Fish extends Food{
public Fish(String name) {
super(name);//訪問父類 Food的構造器,來完成對name的初始化
}
}
Animal類程式碼
package com.extend_.improve;
public class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Dog類程式碼
package com.extend_.improve;
public class Dog extends Animal{
public Dog(String name) {
super(name);
}
}
Cat類程式碼
package com.extend_.improve;
public class Cat extends Animal{
public Cat(String name) {
super(name);
}
}
Master類
package com.extend_.improve;//匯入包就能用包下的所有類了
public class Master {
private String name;
public Master(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void feed(Dog dog, Bone bone)
{
System.out.println("主人 " + name + " 給 " + dog.getName() + " 吃 " + bone.getName());
}
public void feed(Cat cat, Fish fish)
{
System.out.println("主人 " + name + " 給 " + cat.getName() + " 吃 " + fish.getName());
}
}
Poly類程式碼
package com.extend_.improve;
public class Poly {
public static void main(String[] args)
{
Master tom = new Master("湯姆");
Dog dog = new Dog("大黃");
Bone bone = new Bone("大棒骨");
Cat cat = new Cat("貓");
Fish fish = new Fish("魚乾");
tom.feed(dog, bone);
tom.feed(cat, fish);
}
}
執行結果:
從Master類的feed方法看的話,如果動物很多,食物很多,那feed方法就很多,程式碼複用性不高,而且不利於管理和維護。所以引出多型來解決傳統的方法帶來的問題。
306,方法的多型
-
多型的具體體現
(1) 重寫和過載就體現多型
package com.poly_;
public class PolyMethod {
public static void main(String[] args) {
//方法過載體現多型
A a = new A();
//這裡我們傳入不同的引數,就會呼叫不同sum方法,就體現多型
System.out.println(a.sum(1,2));
System.out.println(a.sum(1,2,3));
//方法重寫體現多型
B b = new B();
//根據物件不一樣,我們呼叫的方法不一樣
a.say();
b.say();
}
}
class B //父類
{
public void say()
{
System.out.println("B say() 方法被呼叫...");
}
}
class A extends B
{
public int sum(int n1, int n2)//和下面sum構成過載
{
return n1 + n2;
}
public int sum(int n1, int n2, int n3)
{
return n1 + n2 + n3;
}
public void say()
{
System.out.println("A say() 方法被呼叫...");
}
}
(2)物件的多型(核心,困難,重點)
Animal類的子類是 Dog類和Cat類,主類是Poly類。
Animal類程式碼
package com.extend_.improve;
public class Animal {
public void cry()
{
System.out.println("Animal cry() 動物在叫...");
}
}
Dog類程式碼
package com.extend_.improve;
public class Dog extends Animal{
public void cry()
{
System.out.println("Dog cry() 小狗汪汪叫...");
}
}
Cat類程式碼
package com.extend_.improve;
public class Cat extends Animal{
public void cry()
{
System.out.println("Cat cry() 小貓喵喵叫...");
}
}
Poly類程式碼
package com.extend_.improve;
public class Poly {
public static void main(String[] args)
{
//體驗物件多型特點
//animal 編譯型別就是 Animal,執行型別 Dog
Animal animal = new Dog();
//因為執行時,執行到該行時,animal執行型別是Dog,所以cry就是Dog的cry
animal.cry();
//animal 編譯型別就是 Animal,執行型別 Cat
animal = new Cat();
animal.cry();
}
}
執行結果:
308,多型快速入門
在 305,養寵物引出多型 這節的程式碼裡,我們只需要把Master類程式碼改成如下程式碼就能實現多型。再執行主類Poly類程式碼就能得到相同的結果。
package com.extend_.improve;//匯入包就能用包下的所有類了
public class Master {
private String name;
public Master(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//使用多型機制,可以統一的管理主人餵食的問題
//animal 編譯型別是Animal,可以指向(接收)Animal子類的物件
//food 編譯型別是Food,可以指向(接收)Food子類的物件
public void feed(Animal animal, Food food)
{
System.out.println("主人 " + name + " 給 " + animal.getName() + " 吃 " + food.getName());
}
}
309,向上轉型
因為在編譯階段,能呼叫哪些成員,是由編譯型別決定的
最終執行效果看子類(執行型別)的具體實現,即呼叫方法時,按照從子類(執行型別)開始查詢方法,然後呼叫,規則和前面講的方法呼叫規則一致。
310,向下轉型
比如 Animal animal = new Cat(); Cat cat = (Cat) animal;
311,屬性重寫問題
1,屬性沒有重寫之說,屬性的值看編譯型別
package com.poly_;
public class PolyMethod {
public static void main(String[] args) {
//屬性沒有重寫之說,屬性的值看編譯型別
Base base = new Sub();//向上轉型
System.out.println(base.count);
Sub sub = new Sub();
System.out.println(sub.count);
}
}
class Base//父類
{
int count = 10;//屬性
}
class Sub extends Base{ //子類
int count = 20;//屬性
}
執行結果:
2,instanceof 用於判斷物件的執行型別是否為某某型別 或 某某型別的子型別
package com.poly_;
public class PolyMethod {
public static void main(String[] args) {
B b = new B();
System.out.println(b instanceof B);
System.out.println(b instanceof A);
}
}
class A{} //父類
class B extends A{} //子類
執行結果:
314,動態繫結機制
package com.poly_;
public class PolyMethod {
public static void main(String[] args) {
//a 的編譯型別 A,執行型別 B
A a = new B();//向上轉型
System.out.println(a.sum());
System.out.println(a.sum1());
}
}
class A{
public int i = 10;
//動態繫結機制,getI和執行型別B繫結,呼叫B的getI方法
public int sum()
{
return getI() + 10;
}
public int sum1()
{
return i + 10; //i 是屬性,沒有繫結機制,在A類裡宣告瞭,所以i=10
}
public int getI()
{
return i;
}
}
class B extends A
{
public int i = 20;
public int getI()
{
return i;
}
}
執行結果:
315,多型陣列1
多型陣列:陣列的定義型別為父類型別,裡面儲存的實際元素型別為子類型別
Person類是Student類和Teacher類的父類。
Person類程式碼
package com.poly_;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = 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 String say()
{
return name + "\t" + age;
}
}
Student類程式碼
package com.poly_;
public class Student extends Person {
private int id;
private int score;
public Student(String name, int age, int id) {
super(name, age);
this.id = id;
this.score = score;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
//重寫父類say
public String say()
{
return "學生 " + super.say() + " score = " + score;
}
}
Teacher類程式碼
package com.poly_;
public class Teacher extends Person{
private double salary;
public Teacher(String name, int age, double salary) {
super(name, age);
this.salary = salary;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String say()
{
return "老師 " + super.say() + " salary = " + salary;
}
}
主類程式碼
package com.poly_;
public class PolyMethod {
public static void main(String[] args) {
Person[] persons = new Person[5];
persons[0] = new Person("jack", 20);
persons[1] = new Student("jack",18,100);
persons[2] = new Student("smith",19,30);
persons[3] = new Teacher("scott",30,20000);
persons[4] = new Teacher("king",50,25000);
//迴圈遍歷多型陣列,呼叫say
for(int i = 0; i < persons.length; i++)
{
//persons[i] 編譯型別是Person,執行型別是根據實際情況由JVM來判斷
System.out.println(persons[i].say());//動態繫結機制
}
}
}
執行結果:
316,多型陣列2
在Teacher類裡新增teach方法
//特有方法
public void teach()
{
System.out.println("老師 " + getName() + " 正在講java課程...");
}
在Student類裡新增study方法
//特有方法
public void study()
{
System.out.println("學生 " + getName() + " 正在學java...");
}
主類程式碼
package com.poly_;
public class PolyMethod {
public static void main(String[] args) {
Person[] persons = new Person[5];
persons[0] = new Person("jack", 20);
persons[1] = new Student("jack",18,100);
persons[2] = new Student("smith",19,30);
persons[3] = new Teacher("scott",30,20000);
persons[4] = new Teacher("king",50,25000);
//迴圈遍歷多型陣列,呼叫say
for(int i = 0; i < persons.length; i++)
{
//persons[i] 編譯型別是Person,執行型別是根據實際情況由JVM來判斷
System.out.println(persons[i].say());//動態繫結機制
if(persons[i] instanceof Student)//判斷person[i]的執行型別是不是Student
{
Student student = (Student)persons[i];//向下轉型
student.study();
}else if(persons[i] instanceof Teacher)
{
Teacher teacher = (Teacher)persons[i];
teacher.teach();
}else if(persons[i] instanceof Person) {
//裡面不寫是因為如果persons[i]是Person型別的話,那就不用管
}else {
System.out.println("你的型別有誤,請自己檢查...");
}
}
}
}
執行結果:
317,多型引數
父類 Employee類 程式碼
package com.poly_;
public class Employee { //員工類
private String name;
private double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public double getAnnual()
{
return 12 * salary;
}
}
子類Worker類 程式碼
package com.poly_;
public class Worker extends Employee {//普通員工類
public Worker(String name, double salary) {
super(name, salary);
}
public void work()
{
System.out.println("普通員工 " + getName() + " is working");
}
@Override
public double getAnnual() {
return super.getAnnual();
}
}
子類Manager類 程式碼
package com.poly_;
public class Manager extends Employee{
private double bonus;
public Manager(String name, double salary, double bonus) {
super(name, salary);
this.bonus = bonus;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
public void manage()
{
System.out.println("經理 " + getName() + " is managing");
}
@Override
public double getAnnual() {
return super.getAnnual() + bonus;
}
}
主類程式碼
package com.poly_;
public class Equals {
public static void main(String[] args) {
Worker tom = new Worker("tom", 2500);
Manager milan = new Manager("milan",5000,20000);
Equals equals = new Equals();
equals.showEmpAnnual(tom);
equals.showEmpAnnual(milan);
}
public void showEmpAnnual(Employee e)//形參是父類型別Employee類,實參是子類型別Worker類和Manager類
{
System.out.println(e.getAnnual());//動態繫結機制,方法看執行型別
}
}
執行結果:
318, ==運算子
320,子類重寫equals
結論:
Object類的equals 方法預設就是比較物件地址是否相同,也就是判斷兩個物件是不是同一個物件。
String類的 equals 方法把Object的 equals 方法重寫了,變成了比較兩個字串值是否相等。
Interger類也重寫了Object的 equals 方法,變成了判斷兩個值是否相同。
321,equals課堂練習1
1,判斷兩個Person物件的內容是否相等,如果兩個Person物件的各個屬性值都一樣,則返回true,反之false
思路:Person類中沒有equals方法,所以會到預設的父類 Object類找equals方法,而Object類的equals方法預設是比較是否為同一個物件,看地址是否相同,明顯和題目要求的不符,所以本題要在 Person 類裡重寫 Object類的 equals 方法。不用 == ,因為Person是引用型別。
package com.poly_;
public class Equals {
public static void main(String[] args) {
Person person1 = new Person("jack", 10, '男');
Person person2 = new Person("jack", 10, '男');
System.out.println(person1.equals(person2));
}
}
class Person{ //extends Object
private String name;
private int age;
private char gender;
public Person(String name, int age, char gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public boolean equals(Object obj)//多型引數
{
if(this == obj)//判斷如果比較的兩個物件是同一個物件,則直接返回true
{
return true;
}
if(obj instanceof Person) //是 Person,我們才比較
{
Person p = (Person)obj;//進行向下轉型,因為我需要得到obj的各個屬性
return this.name.equals(p.name) && this.age == p.age && this.gender == p.gender;
}
return false;
}
}
執行結果:
324,hashCode
package com.poly_;
public class Equals {
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
A a3 = a1;
System.out.println("a.hashCode() = " + a1.hashCode());
System.out.println("a.hashCode() = " + a2.hashCode());
System.out.println("a.hashCode() = " + a3.hashCode());
}
}
class A{}
執行結果:
325,toString
1,Object的toString()原始碼
(1)getClass().getName() 類的全類名(包名+類名)
(2)Integer.toHexString(hashCode()) 將物件的hashCode值轉成16進位制字串
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
package com.poly_;
public class Equals {
public static void main(String[] args) {
Monster monster = new Monster("小妖怪", "巡山的", 1000);
System.out.println(monster.toString());
}
}
class Monster{
private String name;
private String job;
private double sal;
public Monster(String name, String job, double sal) {
this.name = name;
this.job = job;
this.sal = sal;
}
}
執行結果:
2,在Monster類裡重寫 toString方法,輸出物件的屬性
快捷鍵 Fn + Alt + insert
package com.poly_;
public class Equals {
public static void main(String[] args) {
Monster monster = new Monster("小妖怪", "巡山的", 1000);
System.out.println(monster.toString());
}
}
class Monster{
private String name;
private String job;
private double sal;
public Monster(String name, String job, double sal) {
this.name = name;
this.job = job;
this.sal = sal;
}
@Override
public String toString() {
return "Monster{" +
"name='" + name + '\'' +
", job='" + job + '\'' +
", sal=" + sal +
'}';
}
}
執行結果:
3,直接輸出一個物件時,toString方法會被預設呼叫
package com.poly_;
public class Equals {
public static void main(String[] args) {
Monster monster = new Monster("小妖怪", "巡山的", 1000);
System.out.println(monster.toString());
System.out.println("==當直接輸出一個物件時,toString方法會被預設的呼叫==");
System.out.println(monster);//等價於 monster.toString()
}
}
class Monster{
private String name;
private String job;
private double sal;
public Monster(String name, String job, double sal) {
this.name = name;
this.job = job;
this.sal = sal;
}
@Override
public String toString() {
return "Monster{" +
"name='" + name + '\'' +
", job='" + job + '\'' +
", sal=" + sal +
'}';
}
}
執行結果:
326,finalize
327,斷點除錯