主頁 > 後端開發 > Java基礎-續

Java基礎-續

2022-02-21 06:52:26 後端開發

方法

概念

在JS中,我們把方法稱之為函式,在java我們稱之為方法,

方法就是一個黑匣子,我們不需要知道內部是如何執行的,只要按照要求呼叫,就能完成必要的功能,

方法申明的語法:

 訪問修飾符 其他修飾 方法回傳值型別  方法名(引數串列){
    方法體;// 這個方法要執行的代碼
 }

參看入口方法:

 public static void main(String [] args){
     System.out.println("主方法");
 }

我們自定義一個方法:

     public static void method(String name,int age){
         System.out.println("name = " + name+";age = " + age);
    }
  • 訪問修飾符 public : 這個方法是一個公共的方法, 

  • 其他修飾 static : 表示這個方法是靜態方法,

  • 回傳值型別 void : 回傳值型別表示這個方法在執行結束之后得到的結果型別, void表示這個方法沒有回傳值,

  • 方法名 method: 自定義的方法的名字,

  • 引數串列(String name,int age) : 這個方法在執行時需要提前設定的值,這里的引數可以寫多個使用“,”,必須指明引數的型別,

  • 方法體 : 寫在{}中的要執行的程式,

方法的命名規則:

  • 不能以數字開頭

  • 不能有特殊符號

  • 不能是java的關鍵字或者保留字符

方法命名規范:

  • 和變數一樣的駝峰規則,第一個單詞全部小寫,其余單詞的首字母要大寫,

  • 方法都是動詞,言簡意賅,

  • 其他的和變數一樣,

方法的申明和呼叫

[1]沒有回傳值也沒有引數的方法

 public static void main(String[] args) {
     //呼叫其他方法
     bark();
 }
 // 沒有回傳值也沒有引數的方法
 public static void bark(){
     System.out.println("This is method bark()");
 }

[2]有引數的方法

有一個引數的方法

 public static void main(String[] args) {
     //呼叫其他方法
     //呼叫有引數的方法 必須傳入對應型別的引數
     String message = "今天是個好日子";
     say(message);
     say("果然是個好天氣");
 }
 // 有一個引數的方法
 /**
  * 有引數的方法,引數的型別是String,引數的名字是msg
  * @param msg
  */
 public static void say(String msg){
     System.out.println("大聲的說出:"+msg);
 }
//  public static void main(String[] args) {
         //呼叫其他方法
         // 呼叫有多個引數的方法   分別按照順序傳入對應型別的引數
         add(1,1);
         int a = 3,b = 4;
         add(a,b);
         eat("披薩",5);
    }
     // 有多個引數的方法
     /**
      * 有兩個引數的方法
      * @param x
      * @param y
      */
     public static void add(int x,int y){
         System.out.println(x +" + "+ y + " = " + (x+y) );
    }
     public static void eat(String food,int count){
         System.out.println("今天吃了" + count + "份" + food);
    }

[3]有回傳值的方法

tips: 當一個方法的回傳值型別不是void

的時候,這時必須在方法中使用return陳述句回傳對應的回傳值型別的資料,

     public static void main(String[] args) {
         //呼叫其他方法
         // 呼叫有回傳值的方法
         String result =  join("您今天","漂亮","非常");
         System.out.println(result);
    }
     //有回傳值的方法
     /**
      * 使用op將msg1和msg2鏈接,并且回傳
      * @param msg1
      * @param msg2
      * @param op
      * @return 回傳值型別為String
      */
     public static String join(String msg1,String msg2,String op){
         String str = msg1 + op + msg2;
         // 回傳對應型別的資料
         return str;
    }

方法堆疊

看一段程式:

 public class Demo4 {
     public static void main(String[] args) {
        int m = 100;
        methodA(m);
        System.out.println("main方法: m = " + m);
    }
 ?
     public static void methodA(int  x){
         int a = x;
         methodB(a);
         System.out.println("methodA : a = " + a);
    }
 ?
     public static void methodB(int y){
         int b = y;
         System.out.println("methodB : b = " + b);
    }
 }

看圖理解上面的程式:

JVM中每次執行一個方法,都會往方法堆疊中放一個堆疊幀

tips:畫圖僅僅是方便理解,并不是所有的內容都完全準確,

methodB執行結束,methodB方法堆疊幀出堆疊,繼續執行methodA,methodA執行結束,methodA堆疊幀出堆疊,繼續執行main方法,

這里也能看出,在任何一個方法中定義的區域變數都是相互獨立的,相互不影響的,

java中的包就和我們檔案系統中的檔案夾是一樣的,純粹的是為了方便管理java的類,

我們可以在專案的src下創建一個package,

包的命名規則:不能有特殊符號,不能數字開頭,不能是關鍵字

包的命名規范:一般都是域名倒著寫,不能有大寫字母,

如果一個類在某一個包中,則整個類最上方是package的申明.

面向物件

面向物件的思想

面向物件是一個思想,并不是一個編程語言,java語言就是實作了面向物件這個思想,

面向物件要相對于面向程序來描述:

我要開車回老家:

面向程序的描述:上車,啟動,給油,出江蘇-->安徽-->河南-->陜西

面向物件的描述:找到汽車,go("陜西"),車自己走,

這個事件中有兩個物件:人和車, 車只是對外提供一個方法 go(目的地), 我們只需要告訴車目的地是什么,車怎么去的,人不需要關心,

現實中有很多事物的思考和設計都是基于面向物件的思想的,

很多事物都是將一些功能封裝在自己內部,然后對外提供了一些可以呼叫的介面,我們可以通過這介面使用這個事務,比如:筆記本電腦的配接器,

面向物件有啥好處?

降低耦合,增強系統可擴展性, 可以讓系統像搭積木一樣搭建,

類和物件的關系

java語言是用類來組織, 類是java語言的最小組織單元,

類是什么?(你是如何認知周邊的事物的?)

類就是一類具有相同或者相似的特征和行為的事物的抽象描述,

跑車:四輪,兩門....... 跑,裝X.....

java中的 public class XXXX{} 是一個類是啥意思?

當JVM啟動的時候,就相當于建立了一個虛擬的世界,這個世界中所有的事物都是存盤在記憶體中的,每一個事物的存盤方式都是由這個事物的類別來確定的,

java中已經定義了大量的資料型別,這些資料型別就是java中類規定的,每個資料型別都會對應一個java類,

資料型別=java類,

所以我們定義任何一個類,就相當于在整個JVM中有創建了一個新的資料型別,

java已有的資料型別:基本型別,String,Scanner,System等等,

我們自定義一個類: public class Hello{  ..... }

一旦使用這個類,這個JVM中就多了一種資料型別 "Hello",

物件是什么?

“萬物皆物件”,

人類----類別,是一個概念,描述人類的特征和行為:姓名,身高,體重,吃飯,思考,,,,

"王大錘"這個具體的人就是一個人類的物件,我們每一個人都是人類這個類別的一個物件,

我們準備一個類:

 public class Animal {  }

創建這個類物件:

語法: 類名 物件名 = new 類名(); 其中類名和變數名的要求是一樣的,

 public static void main(String[] args) {
     // 通過類創建類物件
     Animal a1 = new Animal();
     Animal a2 = new Animal();
 }

上面創建物件的程序就是在記憶體中根據類Animal的申明開辟了一個新的空間,存盤了一些資料,

 

面試題:

類和物件是什么關系?

類是一個抽象的描述,物件是根據類創建的實體

java中的類和物件

java中創建任何類的物件:

 // 申明物件
 類名 物件名;   // 和申明變數是一樣的,
 // 創建物件
 物件名 = new 類名();

所有的我們申明類(型別)都是參考資料型別,

基本型別和參考型別在記憶體中存盤的結構是不一樣的,

JVM的記憶體結構:

所有綠色區域是執行緒共享的,所有的粉色區域是執行緒獨有的,

我們申明的類是一個源檔案,被編譯之后就會成為位元組碼檔案,位元組碼檔案被加載之后,就會放在方法區,

我們申基本型別的變數和物件的存盤狀態:

         int x = 10;
         boolean f = false;
         String name = "大錘";
         // 通過類創建類物件
         Animal a1 = new Animal();

所有的基本型別它的參考和值都是存盤在方法堆疊中的,

所有的參考型別在堆疊中存盤的只是參考和地址,具體的資料是存盤在堆中,

什么是賦值?

 int x = 10;// 給x賦值為10
 int y = x;// 把x值賦值給y
 Animal a1 = new  Animal();
 Animal a2 = a1; // 把a1的值賦值給a2
 ?
 public static void method1(int a){}
 method1(x);// 將x的值賦值給形參a
 public static void method2(Animal ax){}
 method2(a1); // 將a1的值賦值給 ax

所謂賦值就是將這個參考堆疊中的內容復制一份給另外一個參考,

所以: y = x, 就是將x的值10賦值一份給y,

a2 = a1 將a1的地址復制一份給a2, a1和a2就是指向同一塊記憶體的,

面試題: 什么是值傳遞和參考傳遞? 值傳遞和參考傳遞有什么區別?

        java中都是傳值,沒有參考傳遞的概念,

屬性和方法

現實世界中所有的事物都可以使用特征和行為來描述,

我們將特征稱之為屬性,將行為稱之為方法,

我們要在我們的JVM中創建一個類別:Dog,我們應該如何描述,

語法: 使用成員變數表示特征(屬性)

            使用成員方法表示行為(方法)

 public class Dog {
     // 特征 屬性
     String name = "大黃";
     int age = 5;
 ?
     // 行為 方法
     public void sleep(){
         System.out.println("大黃在睡覺zzzzzzzzzzz");
    }
 ?
     public void think(){
         System.out.println("大黃在思考狗生.........");
    }
 }

我們通過Dog類創建物件:

         // 創建一個dog物件
         Dog dog = new Dog();
  Dog dog1 = new Dog();

屬性的訪問

所謂屬性的訪問就是給一個物件的屬性賦值或者獲取這個物件的屬性值,

獲取一個物件的屬性值: 物件名.屬性名,

給一個物件的屬性賦值: 物件名.屬性名 = 值,

        // 創建一個dog物件
        Dog dog = new Dog();
        Dog dog1 = new Dog();
        // 我們可以通過類名
        String name = dog.name;
        String name1 = dog1.name;
        System.out.println("name = "+name);
        System.out.println("name1 = "+name1);
        // 修改dog的name
        dog.name = "旺財";
        // 再次獲取
        name = dog.name;
        name1 = dog1.name;
        System.out.println("name = "+name);
        System.out.println("name1 = "+name1);

tips:修改某一個物件的屬性,不會影響其他物件的屬性值,

方法的呼叫

成員方法(沒有static修飾的方法)

呼叫的語法: 物件名.方法名(實參),

tisp: 成員方法必須使用物件名來呼叫,

成員方法本身就是物件的方法,靜態方法是類的方法(在現實世界中不存在),

人類可以吃飯,吃飯就是一個方法,但是要執行這個方法,必須要具體的人來執行,

 // 呼叫方法
 dog.sleep();
 dog.think();
 dog1.sleep();
 dog1.think();

屬性封裝

按照規范的說法,成員變數就僅僅成員變數,只有經過封裝才是屬性,

java規范-->javaBean: 任何一個合法的java類都是javaBean,

所謂javaBean的規范,就是默認的java類的規范,

在javabean中的屬性的規范是:

 public class Cat {
     // 屬性
     public void setName(String catName){
 
    }
     public String getName(){
         return "小花";
    }
 }

上面的cat類就有屬性 "name", 跟成員變數沒關系,

setName(String catName) : 給屬性name設定值,

getName(): 獲取屬性值,

標準的寫法:

 public class Cat {
     // 私有的成員變數
     private String name;
     // 屬性
     public void setName(String catName){
         name = catName;
    }
     public String getName(){
         return "小花";
    }
 }

有一個私有的成員變數, private String name;

任何一個成員,被private修飾之后,這個成員就只能在當前類中使用,不能在任何其他地方使用,

我們之前的寫法

 public  class Cat{
     String name;
 }
 public class Demo(){
     public static void main(String [] args){
         Cat cat = new Cat();
         cat.name = "小花";
    }
 }

當 name使用private修飾的時候:私有的成員不能在外部訪問

我們認為屬性不應該可以隨意修改,如果不是private修飾就可以在任何地方隨意修改,這是不安全的,

但是被private修飾的成員,無法訪問,所以在當前的類中又提供了public的setter和getter方法用來設定和獲取這個屬性的值,

使用方式:

Cat cat = new Cat();
//cat.name = "小花";
// 設定值
cat.setName("團子");
// 獲取值
String name = cat.getName();
System.out.println("cat的name是:"+name);

這樣的規范讓我們對屬性的操作更麻煩了,但是也更安全了,

給Cat再加一個屬性:age

public class Cat {
	// 其他代碼省略....
    private int age;
    public void setAge(int catAge){
        // 我們可以在這里校驗傳入的值
        if(age > 20){
            age = 20;
        }else{
            age = age;
        }
    }
    public int age(){
        return age;
    }
}

所謂屬性的封裝,就是給成員變數添加setter和getter方法,在外部使用這個屬性的時候,要呼叫這個屬性的setter和getter方法,

屬性封裝的語法規范

[1]成員變數私有化

所有的成員變數都是用private修飾,

javabean規范的一個要求: 任何一個符合javaBean規范的類都不能出現非private的成員變數,

[2]給成員變數添加setter和getter方法

方法要求:兩個方法都是public的成員方法,

setter方法的命名: 成員變數的第一個字母大寫,在前面加上set

比如:成員name -> setName stuScore ->setStuScore

tisp: 成員變數的名字的第二個字母不要大寫,

setter方法是沒有回傳值的,回傳值是void,setter方法必須有一個引數,這個引數的型別和成員變數的型別是一致的,

getter方法命名:成員變數的第一個字母大寫,在前面加上get

比如: 成員name -> getName stuScore ->getStuScore

getter是有回傳值,回傳值型別和成員變數的型別是一致的,getter方法是沒有引數的,

案例1:

定義一個圖書型別 Book,擁有屬性:ISBN,title,author,publisher,price,擁有方法:showInfo()

實作: public class Book {

     private String isbn;
     private String title;
     private String author;
     private String publisher;
     private double price;
 ?
     public void showInfo(){
         String info = title+","+isbn+","+author+","+publisher+","+price;
         System.out.println(info);
    }
     public void setIsbn(String bisbn){
         isbn = bisbn;
    }
     public String getIsbn(){
         return isbn;
    }
     public void setTitle(String btitle){
         title = btitle;
    }
     public String getTitle(){
         return title;
    }
 ?
     public String getAuthor() {
         return author;
    }
 ?
     public void setAuthor(String author) {
         this.author = author;
    }
 ?
     public String getPublisher() {
         return publisher;
    }
 ?
     public void setPublisher(String publisher) {
         this.publisher = publisher;
    }
 ?
     public double getPrice() {
         return price;
    }
 ?
     public void setPrice(double price) {
         this.price = price;
    }
 }

創建物件并且測驗:

 public class Demo2 {
     public static void main(String[] args) {
         Book book = new Book();
         book.setIsbn("987654321");
         book.setTitle("java從入門到入土");
         book.setAuthor("大錘");
         book.setPublisher("有一說一出版社");
         book.setPrice(12.5);
         book.showInfo();
    }
 }

讀程式

程式1:

   public class Test1 {

     public static void main(String[] args) {
         int x = 10;
         System.out.println("x = " + x);// 10
         change(x);
         System.out.println("x = " + x); // 10
    }
     public static void change(int x ){
         System.out.println("x = " + x); // 10
         x = 100;
         System.out.println("x = " + x); // 100
    }
 }

程式2:

public class Cat {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

public class Test2 {
    public static void main(String[] args) {
        Cat c = new Cat();
        c.setAge(5);
        System.out.println(c.getAge());// 5
        change(c);// 將c傳入change方法   賦值
        System.out.println(c.getAge());// 8
    }

    public static void change(Cat c){
        System.out.println(c.getAge());// 5
        c.setAge(8);
        System.out.println(c.getAge()); // 8
    }
}

this關鍵字

 public class Cat {
     private String name;
     public void setName(String catName){
         name = catName;
    }
     public String getName(){
         return name;
    }
 ?
     public void sleep(){
         System.out.println("小貓【"+name+"】正在睡覺zzzzzz");
    }
 }

創建這個類物件

 Cat cat = new Cate();
 cat.setName("小花");

獲取小花的名字:    cat.getName();

在java物件中,默認有一個私有的成員變數 “this”指向當前物件本身,

所以如果我創建了兩個物件:

Cat c1 = new Cat();
Cat c2 = new Cat();

這個this是每個物件私有的,不能在其他的地方呼叫,只能被當前物件自己呼叫,

我們可以在任何的成員方法中使用this(靜態方法中絕對不能使用this)

 public class Cat {
     private String name;
     public void setName(String catName){
         this.name = catName;
    }
     public String getName(){
         return this.name;
    }
 ?
     public void sleep(){
         System.out.println("小貓【"+this.name+"】正在睡覺zzzzzz");
    }
 }

其實在成員方法中使用成員變數或者呼叫成員方法,默認都是使用this呼叫的,只不過this可以省略,

this表示當前物件本身,誰呼叫這個方法,this就表示誰,

斷點查看!

正因為如此,屬性的封裝的常見的做法是:

 private int age;
 public void setAge(int age){
     this.age = age;
 }
 public int age(){
     return age;
 }
 private String name;
 public void setName(String name){
     this.name = name;
 }
 public String getName(){
     return name;
 }

練習

[1]定義一個類Car,擁有屬性color,brand,price, 擁有方法:showInfo() 輸出所有的屬性值, move() 輸出 xxx顏色 xxxx汽車正在移動,

 public class Car {
     private String color;
     private String brand;
     private int price;
 ?
     public void showInfo(){
         System.out.println("當前的汽車的屬性是:" + color+","+brand+","+price);
    }
 ?
     public void move(){
         System.out.println(color + "顏色的" + brand + "車正在移動");
    }
    // setter和getter省略
 }

 public class Test {
     public static void main(String[] args) {
         Car car = new Car();
         car.setColor("紅色");
         car.setBrand("法拉利");
         car.setPrice(50);
         car.showInfo();
         car.move();
    }
 }

[2]定義一個Driver, 擁有屬性: name,age,擁有方法: drive(String v) 傳入交通工具的名字,

創建兩個駕駛員,讓他們分別駕駛不同的交通工具進行測驗,

 public class Driver {
     private String name;
     private int age;
 ?
     public void drive(String v){
         System.out.println(age + "歲的駕駛員" + name + "正在駕駛" + v);
    }
  // setter和getter省略
 }
 public class Demo {
     public static void main(String[] args) {
         Driver driver = new Driver();
         driver.setAge(58);
         driver.setName("老司機");
         driver.drive("火箭");
 ?
         Driver driver1 = new Driver();
         driver1.setAge(18);
         driver1.setName("小司機");
         driver1.drive("小火車");
    }
 }

[3]有一個Cook廚師: 擁有屬性name,age, 擁有方法:cook(String food1,String food),傳入兩個實作,最侄訓傳一道菜的名字為 xxx歲xxxx廚師炒的 《food1炒food2》

 public class Cooker {
     private String name;
     private int age;
     // 有回傳值
     public String cook(String food1,String food2){
         String str = age + "歲的廚師" + name + "炒的 《"+food1 +"炒" +food2 + "》";
         return str;
    }
     // setter和getter省略
 }
 public class Test {
     public static void main(String[] args) {
         Cooker cooker = new Cooker();
         cooker.setAge(38);
         cooker.setName("卡卡西");
         // 呼叫有回傳值的方法
         String result = cooker.cook("西紅柿","番茄");
         System.out.println(result);
    }
 }

成員變數的默認值

java中所有的變數都是必須在賦值(初始化)之后才能使用,

但是我們會發現成員變數不需要賦值就可以使用

因為所有的成員變數都是有默認值的,成員變數的默認值和陣列的默認值一致:

所有的整數型別都是 0或者0L, float是0.0F ,double是0.0, char是空字符\u000 , boolean是 false, 其他型別全部都是null,

當然我們也可以給成員變數賦默認值,一旦設定值,這個類創建的所有的物件的這個屬性值全部都是這個值,

看案例: public class Cat {

     private String name;
     private String color = "黑色";
  // stter和geeter省略
 }
     public static void main(String[] args) {
         Cat cat = new Cat();
         System.out.println(cat.getColor());// 黑色
         Cat cat1 = new Cat();
         System.out.println(cat1.getColor());// 黑
         cat1.setColor("白色");
         System.out.println(cat1.getColor());// 白色
    }

物件之間的關系

[1]將我們自定義的型別作為方法的引數,

看程式1: 類Computer有work方法, 類Corder有work方法需要傳入引數Computer

 public class Computer {
     private String brand;
 ?
     public void work(){
         System.out.println(brand + "品牌的計算機開始自己寫代碼!!!!");
    }
 }
 public class Coder {
     private String name;
     private double faliang;
     // work方法的引數是我們自定義的型別Computer
     public void work(Computer com){
         System.out.println("發量為"+faliang+"的程式猿"+name+"到了一杯咖啡,,,,,");
         // 呼叫形參物件的work方法
         com.work();
    }
 }

測驗程式:

 public class Demo1 {
     public static void main(String[] args) {
         Computer com = new Computer();
         com.setBrand("華為");
         Coder coder = new Coder();
         coder.setName("大錘");
         coder.setFaliang(0.5);
         // 呼叫coderwork方法,傳入上面的com
         coder.work(com);
         System.out.println("-------------------");
         // 跟換一臺計算機開始作業
         Computer com1 = new Computer();
         com1.setBrand("奔馳");
         coder.work(com1);
    }
 }

[2]自定義的型別作為方法的回傳值

案例:準備一個汽車工廠,可以生產汽車,

 public class Car {
     private String color;
     private String brand;
     public void showInfo(){
         System.out.println(color + ":"+ brand);
    };
 }
 public class CarFactory {
     private String brand;
     // 生產汽車
     public Car createCar(String color){
         // 創建一個汽車物件
         Car car = new Car();
         // 設定汽車的屬性
         car.setBrand(brand);
         car.setColor(color);
         // 回傳這個汽車物件
         return car;
    }
 }

測驗程式:

 public class Demo3 {
     public static void main(String[] args) {
         CarFactory factory = new CarFactory();
         factory.setBrand("布加迪-威龍");
         // 創建一輛布加迪
         Car car1 = factory.createCar("藍色");
         car1.showInfo();
         Car car2 = factory.createCar("紅色");
         car2.showInfo();
    }
 }

[3]自定義型別作為一個類屬性

主板是一個型別,主板本身是計算機的屬性

 public class MainBoard {

     private String brand;
     private int price;
     public String getInfo(){
         return "價格為" + price + "的" + brand + "主板";
    }
 }
 public class Computer {
     private String brand;
     // 自定義型別作為其他類的屬性
     private MainBoard mainBoard;
     public void showInfo(){
         System.out.println(brand + "的計算機,使用" +mainBoard.getInfo());
    }
 }

測驗程式:

 public class Demo5 {
     public static void main(String[] args) {
         //創建主板
         MainBoard board = new MainBoard();
         board.setBrand("路基亞");
         board.setPrice(50);
         //創建電腦
         Computer com = new Computer();
         com.setBrand("奔馳");
         // 將上面創建的主要物件設定到computer中
         com.setMainBoard(board);
         //輸出資訊
         com.showInfo();
    }
 }

方法多載

多載是overload直譯過來的,意思是重新加載,

我們可以在一個類中定義同名的方法,通過不同的引數類區分這些方法,在呼叫的時候,JVM會根據傳入的引數自動呼叫對應的方法,

看案例:

我們準備三種不同的交通工具和駕駛員,讓駕駛員分別駕駛三種不同的交通工具,

 public class Train {
     public void move(){
         System.out.println("一輛火車在鐵軌上奔馳.....");
    }
 }
 public class Car {
     public void move(){
         System.out.println("一輛汽車在馬路上奔跑,,,,");
    }
 }
 public class Bicycle {
     public void move(){
         System.out.println("一輛自行車在校園里飛馳....");
    }
 }

創建一個駕駛員:有三個駕駛的方法

 public class Driver {
     // 開火車
     public void drive(Train train){
         System.out.println("老司機-檢查-啟動-觸發--");
         train.move();
    };
     // 開汽車
     public void drive(Car car){
         System.out.println("老司機-啟動-給油-出發--");
         car.move();
    }
     // 自行車
     public void drive(Bicycle bicycle){
         System.out.println("老司機-上車-使勁--登起來--");
         bicycle.move();
    };
 }

tips: 在driver類中有三個 同名的方法drive,但是他們的引數型別不同,所以可以同時存在,這個三個方法就構成了方法的多載,

呼叫測驗:

 public class Demo5 {
     public static void main(String[] args) {
         Driver driver = new Driver();
         // JVM會根據傳入的引數呼叫對應的方法
         Car car = new Car();
         driver.drive(car);
         Train train = new Train();
         driver.drive(train);
         Bicycle bicycle = new Bicycle();
         driver.drive(bicycle);
    }
 }

方法多載

理論上在一個作用域下不能定義同名的變數,

在一個類中不能定義相同的方法,因為相同的方法在呼叫的時候無法區分,

這里的相同的方法是說,名稱相同,引數相同,

方法多載是在同一個類中,同名,但是引數不同的方法,

所謂引數不同,有三種情況:

  • 引數的型別不同,---

  • 引數的個數不同,---

  • 引數的順序不同,---

tip:方法多載和方法的回傳值無關,

看程式:

三種引數不同的情況:

 public class MethodOverload {
     // 引數的型別不同
     public void method(String name){}
     public void method(int age){}
     // 引數個數不同
     public void method1(int x,int y){}
     public void method1(int x,int y,int z){}
     // 引數順序不同
     public void method2(int x,String name){}
     public void method2(String name,int x){}
 }

與訪問修飾符無關: 訪問修飾符不同,不構成多載

與回傳值型別無關:回傳值型別不同,也不構成多載

靜態方法和非靜態方法之間的情況不能“構成”多載

練習:實作一個簡單的計算器類

計算兩個數的加法,減法,乘法

 public class C {
     public long add(long x,long y){
         return x + y;
    };
     public double add(double x,double y){
         return x + y;
    };
     // 其他的計算形式省略
 }

測驗:

 public class Demo6 {
     public static void main(String[] args) {
         C c = new C();
         long add = c.add(1, 2);
         System.out.println(add);
         double add1 = c.add(1.2f, 1.2F);
         System.out.println(add1);
    }
 }

構造方法

創建一個物件的方式

 public class Person(){}
 ?
 Person p1 = new Person();

我們在創建物件的時候,需要使用 new 類名() 我們只有在呼叫方法的時候才會有(),

所以其實我們就是使用 new 關鍵字呼叫了 類的構造方法

在每一個類中都有構造方法,構造方法就是用來創建這個類的物件的,

構造方法的要求:

  • 構造方法的方法名和類名完全一致,

  • 構造方法沒有回傳值,也不能寫void,

和訪問修飾符無關,和引數無關,

案例:

 public class Person {
     // 構造方法
     public Person(){
 ?
    }
     // 實體方法
     public void Person(){}
     // 錯誤的方法
     public person(){}
 }

問題:我們之前寫的所有的類都沒有寫過構造方法,為什么可以使用的呢?

如果一個類沒有顯式的指定構造方法(所謂顯式指定,就是手動寫了構造方法),編譯器會默認給這個類增加一個無引數的,public的構造方法,

如果一個類顯式的指定了構造方法,那么編譯器就不會再給默認的構造方法了,

 public class Person {
     // 構造方法   顯式的指定構造方法
     public Person(){
         System.out.println("創建了一個Person");
    }
 }

目前為止,構造方法只能使用new關鍵字呼叫,

自定義的構造方法

[1] 通過構造方法給屬性設定初始化的值

看問題:構造方法與引數無關,

看下面的類:

 public class Student {
     private String name;
     private int age;
     // 構造方法
     public Student(String name){
         System.out.println("創建一個學生物件");
    }
 }

上面的錯誤原因:當我們使用new關鍵字呼叫Student的構造方法的時候報錯,因為Student構造方法是有一個引數的但是在呼叫的時候沒有傳引數,

當我們指定了一個有引數的構造方法的時候,編譯器不會再給無引數的構造方法了,

所以我們只能呼叫有引數的構造方法,所以必須傳入引數,

 public class Demo7_1 {
     public static void main(String[] args) {
         // 創建學生物件,呼叫構造方法,必須傳入引數
         Student st = new Student("卡卡西");
    }
 }

構造方法的引數有什么用?

我們可以通過構造方法的引數直接初始化物件的屬性值:

我們之前給一個物件的屬性賦值,基本都是通過setter方法賦值,

看下面的情況:

 public class Student {
     private String name;
     private int age;
     // 構造方法 (通過構造方法初始化屬性值)
     public Student(String name,int age){
         this.name = name;
         this.age = age;
    };
     public void showInfo(){
         System.out.println(name+":"+age);
    }
 }

測驗:

Student st = new Student("旗木卡卡西",28);
st.showInfo();// 旗木卡卡 : 28

[2]構造方法的多載

javaBean規范:

  • 任何符合規范的類中都不應該出現非私有的成員變數,

  • 有setter和getter方法的才是屬性,

  • 任何一個符合規范的類都因該有無引數的構造方法,

構造方法也可以多載,看情況:

 public class Student {
     private String name;
     private int age;
     // 構造方法 (通過構造方法初始化屬性值)
     public Student(String name,int age){
         this.name = name;
         this.age = age;
    };
     // 有一個引數的構造方法
     public Student(String name){
         this.name = name;
    }
     // 有五個引數的構造方法
     public Student(int x,int y,int z, String name, int age){
         this.name = name;
         this.age = age;
    }
     // 多載的構造方法
     public Student(){}
 }

呼叫的時候,JVM會自動根據傳入的引數呼叫對應的構造方法:

 Student st1 = new Student();//無引數構造方法
 Student st2 = new Student("佐助");
 Student st3 = new Student("鳴人",15);
 Student st4 = new Student(1,2,3,"小櫻",15);

構造方法中的this

this表示當前物件, 在構造方法中有兩種情況,第一種情況就是表示當前物件,第二種情況就是表示呼叫其他的的構造方法,

看案例:

當使用this呼叫其他構造方法的時候:必須寫在當前的構造方法的第一行,

繼承

基本概念

“繼承”:表示繼承者自動擁有被繼承者的事物(財富),

程式中的繼承和現實中的繼承意思差不多,

在java中繼承發生在兩個類之間或者兩個介面之間,比如A類繼承了B類,A類會自動擁有B類的財富(屬性和方法),

程式實作: public class Animal {

     private String name;
     private int age;
     public void bark(){
         System.out.println(age + "歲的" + name + "在大聲吼叫");
    }
     // setter和getter省略
 }
 /**
  * Dog類沒有自己的屬性和方法
  */
 // 通過extends關鍵字讓Dog了繼承Animal
 public class Dog extends Animal {
 }
 ?

測驗:

 // 創建一個Dog
 Dog dog = new Dog();
 dog.setName("土豆");
 dog.setAge(3);
 dog.bark();

執行結果是正常的,

說明: Dog類中擁有屬性name和age,而且有bark方法,而且bark的執行的內容和Animal是一樣的,

目前能看到的最明顯的作用就是代碼的重用,父類中的定義的方法和屬性,子類都是自動擁有,

語法:類之間的繼承的實作,通過關鍵字extends

 public class 子類  extends 父類{
 

繼承者稱之為子類,被繼承者稱之為父類或者基類,

父類只能有一個, 這個概念其實就是java中但繼承的概念,

所謂單繼承就是:任何一個類最多只能有一個直接父類, 但是一個父類可以有多個子類,

繼承中構造方法的問題

在類的繼承中,構造方法是不能繼承的,

問題:

我給父類Animal一個有引數的構造方法: 編譯器就不會再給無引數的構造方法了,

Dog類報錯:

錯誤的提示是父類中沒有默認的構造器了,

這個問題的產生原因,看圖:

當我們創建了一個子類的時候,記憶體的情況:

當我們創建一個子類的物件的時候,會首先在記憶體中創建一個父類的物件,父類物件的創建使用父類的構造方法,默認情況下就是使用父類的默認構造方法, 當父類沒有默認的構造方法的時候,自然就報錯了,

解決方案:

[1] 在父類中添加默認的構造方法,

[2] 在子類的構造方法,中通過super()主動呼叫父類的有引數的構造方法,

 // 通過extends關鍵字讓Dog了繼承Animal
 public class Dog extends Animal {
     public Dog(){
         // 通過super呼叫父類有引數的構造方法
         super("山芋",6);
    }
 }

當然,也可以這樣寫:

 // 一個引數的構造方法
 public Dog(String name){
     super(name,5);
 }
 // 兩個引數的構造方法
 public Dog(String name,int age){
     super(name,age);
 }

tips: 當在子類的構造方法中使用super呼叫父類的構造方法時,必須寫在第一行,

其實.........任何一個類的默認的構造方法中都默認的呼叫類父類的無引數的構造方法

 public Dog(){
     super(); // 默認的
 }

繼承中的兩個問題

[1] 父類的私有屬性和私有方法是否可以繼承?

 public class Father {

     // 私有的成員變數和方法
     private String name;
     private void say(){
         System.out.println("My name is "+name);
    }
 }
 public class Son extends Father {
 }

在子類中使用父類私有的成員:

給父類的私有的成員變數添加setter和getter

測驗:

子類中可以使用父類的getName和setName方法:

 Son son = new Son();
 // son.name
 son.setName("鳴人");
 System.out.println(son.getName());

問題: son.setName("鳴人") setName 中有 this.name = name; 這個this是誰?

所有的父類的私有的成員,在子類中都是不能直接使用的,表面上來看就是沒有繼承,

[2]父類的靜態的方法和成員是否可以繼承

靜態方法和靜態成員是可以被繼承,

 在父類中添加一個靜態的方法

 public class Father {

     public static void showStaticInfo(){
         System.out.println("我是父類的靜態方法");
    }
  // ........
 }

使用子類物件呼叫這個靜態方法:

 Son son = new Son();
 son.showStaticInfo();

結果:正常呼叫而且執行,

從現象來看,子類整的繼承了父類的靜態的方法,

static修飾的任何成員都是屬于類的,不是屬于物件的,應該直接使用 類名.方法名, 或者 類名.屬性名, 不應該使用物件呼叫, 而且一定要使用這個成員所申明的位置的類直接呼叫,

本質上來說,靜態方法和成員是不能被子類繼承的,但是我們可以使用子類的類名或者物件直接呼叫父類的靜態方法, 但是這種用法是不規范的,

繼承-> 擴展

繼承的關鍵字是extends,翻譯過來是擴展, 所以其實子類就是擴展于父類,所以子類大于父類,就像我們上面畫的記憶體圖,

看案例:

 public class Animal {
     private String name;
     public void bark(){
         System.out.println("動物"+name+"在吼叫");
    }
     // ....
 }
 ?
 在子類中擴展自己專有的屬性和方法
 public class Dog extends Animal {
     // 父類的屬性和方法無法滿足子類的需求
     // 可以定義自己的屬性和方法
     private String color;
     public void lookHome(){
         System.out.println(color + "顏色的" + getName() + "正在看家....");
    }
 }

看程式:

 public class Demo10 {
     public static void main(String[] args) {
         Dog dog = new Dog();
         dog.setName("大黃"); // 繼承的屬性
         dog.setColor("黑色");// 自己擴展的屬性
         dog.bark();// 繼承的方法
         dog.lookHome();// 自己擴展的方法
    }
 }

看記憶體圖:

 

 

 

 

 

 

本文來自博客園,作者:{瀟瀟消消氣},轉載請注明原文鏈接:{https://www.cnblogs.com/xiaoxiaodeboke/}

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/429261.html

標籤:其他

上一篇:CMake出錯的處理

下一篇:java記憶體區域模型和詳解

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more