面向對象2 訪問修飾符 | | private | default | protected | public | | | | | | | | 當前類 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_che ...
面向對象2
訪問修飾符
private | default | protected | public | |
---|---|---|---|---|
當前類 | ✔️ | ✔️ | ✔️ | ✔️ |
同一個包 | ✖️ | ✔️ | ✔️ | ✔️ |
不同包 | ✖️ | ✖️ | ✔️ | ✔️ |
無關類 | ✖️ | ✖️ | ✖️ | ✔️ |
參數傳遞
基本類型和String類型的參數傳遞(值傳遞)
在進行基本類型的參數傳遞是,傳的是參數的值,並不是參數本身!當main方法調用其他方法時,改變的只是被調用的方法的參數,與main方法內的參數無關。當方法執行結束後,所有的參數對象都會被gc自動銷毀回收。
引用類型的參數傳遞(記憶體地址傳遞)
引用數據類型非常多,大致包括:
類、 介面類型、 數組類型、 枚舉類型、 註解類型
在進行引用類型的參數傳遞是,傳的是引用類型的參數地址!當main方法調用其他方法時,進行操作的是賣弄傳進來的地址,當方法執行結束後,並不影響更改後的參數對象。
public class Test01 {
public static void test(int a, int[] arr){
a = 3;
int[] arr1 ={5,4,3,2,1};
arr[0] = 10;
arr = arr1;
}
public static void main(String[] args) {
int[] arr={1,2,3,4,5};
int a = 0;
test(a,arr);
System.out.println(arr[0]);
}
}
// 輸出的結果:
// a = 0;
// arr = {10,2,3,4,5};
final常量
特點
- 被final修飾的類不可以被繼承
- 被final修飾的方法被不可以被重寫
- 被final修飾的變數不可以更改值
- 被final修飾的引用不可以存儲其他對象的記憶體地址
封裝
封裝的目的
提供一個統一的用來設置對象屬性和訪問對象屬性的入口
封裝的要求
- 所有成員的變數全部私有
- 需要提供公有的set和get方法來提供對象成員變數的訪問
- 需要提供一個無參構造方法(必須是public所修飾的)用來給外界創建對象
Java Bean
想象一下存在這樣一個箱子,其內部被分割成幾個格子,每個格子用來存放特定的物品,工人取出或者放入物品後封箱,然後叫了個快遞把箱子發出去了。這個箱子就是 Java Bean 啊,取出、放入就是getter、setter,物品就是屬性,封箱發出就是序列化和傳輸。
// 舉個慄子
public class Product {
private int id;
private String name;
private double price;
private double stock;
public Product(){}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public double getStock() {
return stock;
}
public void setStock(double stock) {
this.stock = stock;
}
}
繼承(Java中只支持單繼承)
Java種的繼承解決的是代碼復用的問題(父類:共性抽取。子類:功能表現-功能拓展)
每一個類都只能有一個父類,但是可以有許多子類
繼承帶來的好處
- 提高了代碼的復用性,提高了軟體開發的效率
- 繼承的出現讓類和類之間產生了關係,提供了多態的前提
// 舉個一個慄子
// 新建一個父類Person
public class Person {
public String name;
public int age;
public void eat(){
System.out.println("Person => eat()");
}
}
// 新建一個子類Student繼承Person
public class Student extends Person{
public int sno;
public void study(){
System.out.println("Student => study()");
}
}
// 新建一個子類Teacher繼承Person
public class Teacher extends Person{
public int tno;
public void teach(){
System.out.println("Teacher => teach()");
}
}
// 主運行類,Student實例化的對象,擁有Person類里的參數和方法
public static void main(String[] args) {
Student student1 = new Student();
student1.name = "student01";
student1.sno = 10001;
student1.eat();
student1.study();
}
繼承里的構造方法
當new了子類新對象的時候(即對子類對象進行初始化的時候),父類的構造方法也會執行,且其優先順序在子類的構造方法之前,因此父類必須擁有無參構造!
(⭐)對於子類的構造方法而言,不管是子類的是有參構造方法,還是無參構造方法,都是預設調用父類的無參構造方法,所以不管父類的構造方法是否有做對象的初始化,都必須將父類的無參構造方法給顯式的定義出來
super 的三種用法
- 在子類的構造方法種的第一行,用來訪問父類的指定構造函數,如果不寫,則預設訪問父類的無參構造
- 在子類中有和父類名字相同的成員變數時,用於訪問父類的指定成員變數(阿裡編程規範里不允許使用)
- 在子類有和父類完全相同的方法的時候(方法名相同&參數的數量,順序,類型相同),訪問父類的方法
this 的三種用法
- 在當前子類的構造方法時,會調用自己的其他構造方法
- 訪問自己的成員變數
- 訪問當前類的其他方法
// 舉個一個慄子
// 新建一個父類Person
public class Person {
public String name;
public int age;
// 重寫無參構造
public Person(){
System.out.println("Person => Person()");
}
// 重寫有參構造
public Person(String name, int age) {
System.out.println("Person => Person(name,age)");
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("Person => eat()");
}
}
// 新建一個子類Student繼承Person
public class Student extends Person{
public int sno;
// 重寫無參構造
public Student(){
super(); // 調用父類的無參構造,如果不寫預設生成
System.out.println("Student => Student()");
}
// 重寫有參構造
public Student(String name, int age, int sno) {
super(name, age);// 調用父類的有參構造,如果不寫預設調用無參構造,會爆紅!!!!!!!
this.sno = sno;
}
public void study(){
System.out.println("Student => study()");
}
}
// 主運行類,Student實例化的對象時,先調用父類Person的無參構造,再調用自己的構造方法
public static void main(String[] args) {
// 通過子類的無參構造,實例化對象(父類無參構造 => 子類無參構造)
Student student1 = new Student();
// 通過子類的有參構造,實例化對象(父類有參構造 => 子類有參構造)
Student student2 = new Student("Robot01",18,10001);
}
@Override註解
-
聲明當前方法重寫了父類方法
-
如果被標記的方法沒有重寫父類方法,編譯則無法通過
// 新建一個父類Person
public class Person {
public String name;
public int age;
public void eat(){
System.out.println("Person => eat()");
}
}
// 新建一個子類Student繼承Person
public class Student extends Person{
public int sno;
public void study(){
System.out.println("Student => study()");
}
@Override
public void eat(){
System.out.println("Student => eat()");
}
}
抽象類(abstract)
抽象類的概念
抽象類是用來捕捉子類的通用性的,它不能被實例化,只能用作子類的超類,抽象類是被用來創建子類的模板,如果父類中的方法無法滿足所有子類的需求,這個方法就應該是一個抽象方法
抽象類的特點
- 抽象類本身不可以使用new 創建對象
- 必須通過子類來創建對象
- 子類必須覆寫父類當中所有的抽象方法
- 抽象類中可以定義非抽象方法,用於給子類繼承使用,自己無法調用
- 抽象類中可以定義成員變數,用於給子類繼承使用,自己同樣無法調用
- 抽象類中可以定義構造方法,用於給子類繼承使用,自己同樣無法使用
- 抽象類中可以不定義抽象方法
- 如果一個類繼承了抽象類,卻沒有覆寫父類的所有抽象方法,那麼這個類,一定也是一個抽象類
抽象類實現
// 新建抽象類Pic,定義抽象方法area()
public abstract class Pic {
public abstract void area();
}
// 新建類TriAngle,覆寫抽象方法area()
public class TriAngle extends Pic {
@Override
public void area() {
System.out.println("TriAngle => area()");
}
}
// 新建主運行類,測試代碼
public static void main(String[] args) {
TriAngle triAngle = new TriAngle();
triAngle.area();
}
介面(interface)(變向實現多繼承)
介面的概念
介面相比抽象類,抽象的更加徹底,介面只能描述子類所應當具備的方法,但是沒有具體的實現,將功能的定義和實現進行分離,給程式解耦
在 JDK1.7 之後介面中可以定義常量,在 JDK1.8 之後介面中可以定義帶有方法體的預設方法(default)和靜態方法(static),所有版本中都不可以定義普通方法,也不可以定義構造函數,成員變數
介面的特點
- 允許多實現(相當於多繼承)
- 不允許定義成員變數和非抽象方法
- 可以定義抽象方法和靜態常量
- 介面相當於是功能的集合
// 定義介面
public interface Brake {
void brakeRole();
}
public interface EnvironmentProtect {
void emission();
}
public interface Safe {
void safeRule();
}
// 定義類Car繼承介面
public class Car implements Brake,EnvironmentProtect,Safe{
@Override
public void brakeRole() {
System.out.println("Brake => breakRole()");
}
@Override
public void emission() {
System.out.println("EnvironmentProtect => emission()");
}
@Override
public void safeRule() {
System.out.println("Safe => safeRule()");
}
}