1. 程式人生 > >Java高級教程

Java高級教程

eth 被調用 管理 rst 年齡 rgs 接口的應用 權限 文件讀寫

目錄

  • 1.Java面向對象方法
    • 1.1. 創建類和對象的方法
    • 1.2. this的使用
    • 1.3. 靜態域和靜態方法
      • 1.3.1. 靜態域:屬於類的級別
      • 1.3.2.靜態常量
      • 1.3.3 靜態方法
      • 1.3.4. 工廠方法
      • 1.3.5. main方法
    • 1.4. 對象構造
      • 1.4.1. 對象重載
      • 1.4.2. 類的構造器以及初始化
    • 1.5. 包
  • 2. Java的繼承
    • 2.1. 繼承的語法
    • 2.2. 繼承中的對象轉型
      • 2.2.1. 對象向上轉型
      • 2.2.2. 對象向下轉型
    • 2.3. 阻止繼承:final類和方法
    • 2.4.抽象類和抽象函數
      • 2.4.1. 定義方法與語法特征
      • 2.4.2. 為什麽用抽象類?
  • 3. 包的訪問權限
    • 3.1. 將類放到包中
    • 3.2. 包的訪問權限有哪些
  • 4. 接口
    • 4.1. 什麽是接口
    • 4.2.接口語法
    • 4.3. 接口的應用
  • 5. Java的異常處理
    • 5.1. JDK異常的分類和try-catch捕捉
    • 5.2. 用戶自定義的異常處理
  • 6. Java中的IO
    • 6.1. IO的定義和分類,以及字節流基本用法:
    • 6.2. 大文件的讀寫方法和字符流的使用
      • 1. 大文件讀寫
      • 2.字符流
    • 6.3. 節點流和處理流
      • 1. 處理流: BufferedReader:字符輸入處理流
  • 7.內部類和匿名內部類
    • 7.1. 內部類
    • 7.2. 匿名內部類

1.Java面向對象方法

  • 繼承
  • 封裝
  • 多態

this的用法

  • 引用隱式參數
  • 調用該類其他的構造器

super的用法

  • 調用超類方法
  • 調用超類的構造器

1.1. 創建類和對象的方法

對象和引用的一個關系圖:

技術分享圖片
技術分享圖片

模板:

class ClassName {
  
  field1 // 屬性: 描述類的狀態
  field2
  ...
  constructor1
  constructor2
  ...
  method1  // 方法: 描述類的行為
  method2
}

下面是一個簡單的實例

public class Main {
    public static void main(String[] args) throws IOException {
      // 對象的使用方法  
      // 對象.變量: staff.name
      // 對象.函數(): staff.getname()
        Employee[] staff = new Employee[3];

        staff[0] = new Employee("Zhang", 75000, 1977, 12,15);
        staff[1] = new Employee("Li", 23000, 1932, 3,5);
        staff[2] = new Employee("Zhang", 56444, 1964, 6,21);

        for (Employee e: staff){
            e.raiseSalary(5);
        }

        for (Employee e: staff){
            System.out.println("name=" + e.getName() + ", salary=" + e.getSalary() + ", hireday=" + e.getHireDay());
        }
    }
}


// 一個類可以有無限多個對象
class Employee{

    // 三個實例域用來存放將要操作的數據
    private String name;
    private double salary;
    private LocalDate hireDay;

    // 構造器(與類名同名),總是伴隨著new操作符的執行而被調用  
    // 每個類可以有一個以上的構造器
    // 如果類中沒有構造器,java會默認有一個構造器用於初始化
    // 但是如果類的構造器大於1個的話,需要自己構造默認構造器
    // 構造器可以有0,1,...等多個參數
    // 構造器沒有返回值,即沒有void
    // 構造器總是伴隨著new的操作一起調用
    
    public Employee(String n, double s, int year, int month, int day){
        name = n;
        salary = s;
        hireDay = LocalDate.of(year, month, day);
    }
    // 需要獲得或者設置實例域的值,需要提供以下三個內容:  
    // (1).一個私有的數據域
    // (2).一個公有的域訪問器方法
    // (3).一個公有的域更改器方法
    public String getName() {
        return name;
    }

    public double getSalary() {
        return salary;
    }

    public LocalDate getHireDay() {
        return hireDay;
    }

    public void setHireDay(LocalDate hireDay) {
        this.hireDay = hireDay;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    // class方法有兩個參數: 顯示參數(括號內部的參數) + 隱式參數(引用該方法的對象)
    // 用this來表示隱式參數,表示使用該方法的對象
    public void raiseSalary(double rate){
      // 可以直接訪問類的屬性
        double raise = this.salary * rate / 100;
        this.salary = this.salary + raise;
    }
}

1.2. this的使用

  • 使用this調用成員變量和成員函數
  • 使用this調用構造函數
class Person{
  String name;
  int age;
  String address;

  Person(){
    System.out.println("無參數");
  }

  Person(String s, int a){
    this.nanme = s;
    this.age = a;
  }
  // this可以調用構造函數
  Person(String s, int a, String s2){
    this(s, a);
    this.address = s2;
  }

  // this為使用該方法的對象,也稱為類的隱式參數
  void talk(){
    System.out.println("my name is " + this.name)
  }

}

1.3. 靜態域和靜態方法

1.3.1. 靜態域:屬於類的級別

  • 一般變量: 對象.變量
  • 靜態變量: 類名.變量 + 對象.變量

技術分享圖片
技術分享圖片

如果將一個域定義為static, 每個類中只有一個這樣的域, 而每個對象對於所有的實例域卻有自己的一份拷貝, 比如我們創建一個class:

class Employee {
  private static int nextID = 1;
  private int id;
}

如果有1000getEmployee類的對象,就有100個實例域id,但是只有一個靜態域nextId

1.3.2.靜態常量

// 1000個對象有1000個拷貝
public final double PI = 3.14;
// 1000個對象只有一個PI
public static final doube PI = 3.14;

1.3.3 靜態方法

靜態方法是一種不能向對象實施操作的方法,只能通過類名調用,也就是說沒有this隱式參數

  • 非靜態方法: employee.getNextID()
  • 靜態方法: Employee.getNextID()
  • 靜態函數中不能使用非靜態變量(非靜態域)

1.3.4. 工廠方法

1.3.5. main方法

public class Main {
  // main是一個靜態方法,不對任何對象進行操作  
  // 事實上,再啟動程序的時候沒有任何對象,靜態main方法將執行並創建程序需要的對象
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

1.4. 對象構造

1.4.1. 對象重載

如果多個方法有相同的名字、不同的參數,便產生了重載,編譯器根據傳入的參數自動旋轉哪個方法

StringBuilder msg = new StringBuilder();
StringBuilder msg = new StringBuilder("To do: \n");

1.4.2. 類的構造器以及初始化

class Employee {
  private static int nextId;

  private int id;
  private String name;
  private double salary;

  //初始化塊中初始化值
  {
    id = nextId;
    nextId++;
  }
  // 構造器中初始化值
  public Employee(){
    name = ""
    salary=0;
  }
  public Employee(String n, double s){
    this.name = name;
    this.salary = s;    
  }

  
}

1.5. 包

管理class文件的

  • 導入類文件: import java.util.*
  • 將類文件放到包中: package com.horstman.corejava

2. Java的繼承

一個類得到了另外一個類的成員變量和成員函數

Java只支持單繼承,不允許多繼承

技術分享圖片

2.1. 繼承的語法

public class Main {
    public static void main(String[] args) {
        // 生成子類的過程
        student st = new student("zhang", 20, 6);
        st.introduce();
    }
}

// 將重復代碼放到父類中去
class Person{
        String name;
        int age;
        public Person(){
            System.out.println("Person無參數");
        }

        public Person(String name, int age){
            this.name = name;
            this.age = age;
        }

        void eat(){
            System.out.println("吃飯");
        }

        void introduce(){
            System.out.println("my name is " + this.name + ", my age is " + this.age);
        }
}

class student extends Person{

    int grade;
    // 自動繼承父類的成員變量和成員函數
    // 在子類的構造函數中,必須調用父類的構造函數
    public student(String name, int age, int grade) {
        super(name, age);
        this.grade = grade;
    }

    // 子類可以寫自己的成員函數
    void study(){
        System.out.println("Study");
    }

    // 復寫 父類的方法
    // 1. 在具有父子關系的兩個類當中
    // 2. 父類和子類中各有一個函數,這兩個函數的定義(返回值類型,函數名和參數列表)完全相同
    @Override
    void introduce() {
        super.introduce();
        System.out.println("my grade is " + this.grade);
    }
}

2.2. 繼承中的對象轉型

2.2.1. 對象向上轉型

將子類的對象賦值給父類的引用

// s是學生,也是人
//s: 變量(name,age,address) + 函數(introduce, study)
Student s = new Student();
//p:變量(name,age) + 函數(introduce)
Person p = s;

// 一個引用能夠調用哪些成員變量和函數,取決於這個引用的類型(p引用person,看p前面的類型)
// 一個引用調用的哪個方法,取決於這個引用所指向的對象(p指向的是student對象,調用student方法)
p.name = "zhang";
p.age = 12;
// p.address = "bj" 不可以使用(他說)
p.introduce(); // 調用的是子類的Introduce()
// p.study()  不可以使用 

2.2.2. 對象向下轉型

Student s1 = new Student();
Person p = s1;
Student s2 = (Student)p;

2.3. 阻止繼承:final類和方法

  • 將類定義為final後,無法繼承
  • 將類的方法定義為final後,子類無法覆蓋該方法

public class final Mother extends Person{
  ....;
}  


public class student extends Person{
  public final String getName{
    ....;
  }
}

2.4.抽象類和抽象函數

面向對象思想:先抽象,後具體

2.4.1. 定義方法與語法特征

  • 只有函數的定義,沒有函數體的函數
  • 抽象類不能生成對象(如果能的話,可能調用抽象函數,但是抽象函數沒有函數體,無法解釋)
  • 抽象類天生是當爹的,只能被繼承,它的子類可以生成對象
  • 如果一個類中包含抽象函數,那麽類必須被聲明為抽象類
  • 如果一個類中沒有抽象函數,也可以聲明為抽象類
  • 抽象類可以有構造函數
public class Main {
    public static void main(String[] args) {
        Person p = new Chinese();
        p.eat();
    }
}

// 抽象類
abstract class Person{
        String name;
        int age;
        public Person(){
            System.out.println("Person無參數");
        }

        public Person(String name, int age){
            this.name = name;
            this.age = age;
        }
        // 抽象函數
        abstract void eat();

        void introduce(){
            System.out.println("my name is " + this.name + ", my age is " + this.age);
        }
}

class Chinese extends Person{

    Chinese(){
      super();
      System.out.println("chinese的構造函數");
    }
    @Override
    void eat() {
        System.out.println("用筷子吃飯");
    }
}

2.4.2. 為什麽用抽象類?

  • 抽象類表達的是一種抽象的概念,屬於比父類還抽象的類
  • 抽象函數可以檢查子類是否復寫了抽象函數,是一種檢測機制,檢測是否子類有沒有寫應該復寫的抽象函數
public class Main {
    public static void main(String[] args) {
        Person[] p = new Person[2];
        
        p[0] = new Employee("zhang",5000,2018,10,12);
        p[1] = new Student("Li", "CS");
      // i.getDescription()中由於不能構造抽象類Person的對象,所以變量i永遠不會引用person對象,而是引用employee或者student子類的具體對象  
        for (Person i:p){
            System.out.println(i.getName() + "," + i.getDescription());
        }
    }
}

// 將重復代碼放到父類中去
abstract class Person{
    abstract String getDescription();
    String name;
    
    Person(String name){
        this.name=name;
    }

    public String getName() {
        return name;
    }
}

class Employee extends Person{
    double salary;
    LocalDate hireday;
    
    Employee(String name,double salary, int year, int month, int day){
        super(name);
        this.salary = salary;
        hireday = LocalDate.of(year,month, day);
    }

    public double getSalary() {
        return salary;
    }

    @Override
    public String getName() {
        return super.getName();
    }

    public LocalDate getHireday() {
        return hireday;
    }
    
    @Override
    String getDescription() {
        return String.format("an employee with a salary of %.2f", salary);
    }
    
}

class Student extends Person{
    String major;
    
    Student(String name, String major){
        super(name);
        this.major = major;
    }

    @Override
    public String getName() {
        return super.getName();
    }

    public String getMajor() {
        return major;
    }
    
    @Override
    String getDescription() {
        return "a student majoring in" + major;
    }
}
zhang,an employee with a salary of 5000.00
Li,a student majoring inCS

3. 包的訪問權限

3.1. 將類放到包中

什麽是軟件包?

技術分享圖片

怎麽講類放到軟件包中?

  • 將類放到一個包中,需要使用packcage “包名”
  • 編譯時需要使用 -d參數,該參數的作用是依照包名生成相應的文件夾
  • 一個類的全名: 包名 + . + 類名:mars.Test
  • 包名的命名規範
    • 一般小寫
    • 一般是域名倒過來寫: io.github.com.haochen95;
package mars;

class Test{
  public static void main(String[] args){
    System.out.println("package")
  }
}

3.2. 包的訪問權限有哪些

訪問權限 含義 包內可否使用 包之間可否使用 包內繼承 包間繼承
public 公有權限 Yes Yes Yes Yes
private(很少修飾類) 私有權限 No No No No
default 包級別訪問權限 Yes No Yes No
protected(不修飾類) 受保護權限 Yes No Yes Yes(只有子類才能使用)
  • 如果子類和父類不在同一個包中,子類確實繼承到了父類的成員變量和成員函數,然後再檢查權限,看是否能夠使用
  • public > protected > default > private

4. 接口

4.1. 什麽是接口

技術分享圖片

4.2.接口語法

  • 使用Interface定義
  • 接口中的方法全是抽象方法
  • 接口中的方法全是public權限
  • 實現接口使用implements關鍵字
  • 一個類可以實現多個接口
  • 一個接口可以繼承多個接口
// 定義接口
interface USB{
  public void read();
  public void write();
}
interface WIFI{
  public void open();
  public void close();
}
// 繼承接口
class Phone implements USB,WIFI{
  public void read(){
    System.out.println("USB READ")
  }
  public void write(){
    System.out.println("USB WRUTE")
  }
  public void open(){
    System.out.println("WIFI OPEN")
  }
  public void close(){
    System.out.println("WIFI CLOSE")
  }
}
// 主函數中調用  
class Test{
  public static void main(String[] args){
    Phone phone = new Phone();
    USB usb = phone;
    usb.read();
    usb.write();

    WIFI wifi = phone;
    wifi.open();
    wifi.close();
  }
}

4.3. 接口的應用

  • 在繼承中,可以將重復代碼放到父類中
  • 但是所有子類都需要使用類似的方法體,可能使用接口更加的合適
  • 接口定義了一種標準,接口只定義應該有這些方法,但是不關心方法的具體實現方法,由每個子類自己去實現

5. Java的異常處理

5.1. JDK異常的分類和try-catch捕捉

  • 異常:終端了正常指令流的事件;
  • 程序在異常處會中斷,退出程序
  • 使用try-catch捕捉異常(對於track error必須使用)

技術分享圖片

try{
  System.out.println(4); // 沒出異常,繼續執行/出了異常跳到catch執行,再繼續執行
}
catch(Exception e){
  e.printStackTrace();
  System.out.println(5);
}
finally{   // 異常出不出 都會執行這個程序-----主要用於IO流的關閉文件代碼
  System.out.println(6);
}
System.out.println(7);

5.2. 用戶自定義的異常處理

  • throw和throws關鍵字的用法
public void setAge(int age){
  if(age<0){
    // untrack excaption---程序運行到這裏就會終止
    RuntimeException e = new RuntimeException("年齡不能為負數");
    throw e;
    // track excaption --- 必須用try-catch進行捕捉或者聲明(throws Exception)放在類聲明中
    Exception e = new Exception("年齡不能為負數")
    throw e;
  }
}

6. Java中的IO

6.1. IO的定義和分類,以及字節流基本用法:

  • IO的目標:從數據源(文件,鍵盤,網絡)中讀取數據,從數據寫入到數據目的地(文件,屏幕,網絡)當中
  • 輸入和輸出流在Java中都設置成一種"管道", IO流也是一種對象
  • IO的分類
    • 輸入輸出流
    • 字節流,字符流
    • 節點流,處理流

    • IO流中的核心類: InputStream(抽象類) <- FileInputStream, OutputStream(抽象類) <-FileoutputStream
      -InputStream: int read(byte[] b, int off, int len),返回讀取了多少字節的數據
      -OutputStream: void write(byte[] b, int off, int len)

import java.io.*;
// 字節流
class Test{
  public static void main(String[] args){
    // 聲明輸入流引用
    FileInputStream fis = null;
    // 聲明輸出流引用
    FileoutputStream fos = null;
    try{
      // 字節流-讀數據: 生成代表輸入流的對象
      fis = new FileInputStream("D:/from.txt");
      // 生成代表輸出流的對象
      fos = new FileoutputStream("D:/to.txt");
      // 生成一個字節數組
      byte[] buffer = new byte[100];
      // 調用輸入流的read方法,讀取數據
      int temp = fis.read(buffer, 0, 100);
      // 寫入到文件中
      fos.write(buffer,0, temp);
      String s = new String(buffer); // 將字節轉為字符
      // 去除空格
      s = s.trim();
      System.out.println(s);
    }
    catch(Exception e){
      System.out.println(e);
    }
  }
}

6.2. 大文件的讀寫方法和字符流的使用

1. 大文件讀寫

import java.io.*;
class Test{
  public static void main(String[] args){
    FileInputStream fis = null;
    FileoutputStream fos = null;
    try{
      fis = new FileInputStream("D:/from.txt");
      fos = new FileoutputStream("D:/to.txt");
      byte[] buffer = new byte[100];
      // 大文件:循環讀取
      while(true){
        int temp = fis.read(buffer, 0, 100);
        // 讀到文件最後的時候,read返回-1
        if (temp == -1){
          break;
        }
        fos.write(buffer,0, temp);
      }
    }
    catch(Exception e){
      System.out.println(e);
    }
    finally{
      // 一定要在finally中關閉文件管道
      try{
        fis.close();
        fos.close();
      }
      catch(Exception e){
      System.out.println(e);
      }
    }
  }
}

2.字符流

  • 讀寫文件是,以字符為基礎
  • 核心方法:Reader(抽象類) <- FileReader, Writer(抽象類) <-FilWriter
    -Reader: int read(char[] b, int off, int len),返回讀取了多少字節的數據
    -Writer: void write(char[] b, int off, int len)
import java.io.*;
class Test{
  public static void main(String[] args){
    FileReader fr = null;
    FilWriter fw = null;
    try{
      fr = new FileReader("D:/from.txt");
      fw = new FIleWriter("D:/to.txt");
      char[] buffer = new char[100];
      int temp = fr.read(buffer,0,buffer.length);
    }catch(Exception e){
      System.out.println(e);
    }
        finally{
      // 一定要在finally中關閉文件管道
      try{
        fr.close();
        fw.close();
      }
      catch(Exception e){
      System.out.println(e);
      }
    }
  }
}

6.3. 節點流和處理流

1. 處理流: BufferedReader:字符輸入處理流

  • readline功能
  • 生成BufferedReader對象的方法:
    • BufferedReader in = new BufferedReader(new FileReader("D:/from.txt"))
    import java.io.*;
    class Test{
    public static void main(String[] args){
      FileReader fileReader = null;
      BufferedReader bufferedReader = null;
      try{
        fileReader = new FileReader("D:/from.txt");
        bufferedReader = new BufferedReader(fileReader);
        // 按照一行一行的讀取
        Strign line = null;
        while(true){
          line = bufferedReader.readline();
          if (line == null){
            break;
          }
          // 打印每一行
          System.out.println(line)
        }
    
      }
      catch(Exception e){
        System.out.println(e);
      }
      finally{
        // 一定要在finally中關閉文件管道
        try{
          fileReader.close();
          bufferedReader.close();
        }
        catch(Exception e){
        System.out.println(e);
        }
      }
    }
    }

7.內部類和匿名內部類

7.1. 內部類

  • 生成內部類的對象: A.B b = new A().new B();

class A{
  int i;
  // 內部類:A&B.class
  class B{
    int j;
    int funB(){
      // 內部類可以隨意使用外部類的變量
      int result = i+j;
      return result;
    }
    
  }
}

class test{
  public static void main(String[] args){
    // 生成內部類的對象
    A a =new A();
    A.B b = new A().new B();

    a.i = 3;
    b.j = 1;
    b.funB();  // 結果是 3 + 1 = 4;
  }
}

7.2. 匿名內部類

interface A{
  public void dosomething{};
}

class B{
  public void fun(A a){
    System.out.println("B lei");
    a.dosomething();
  }
}

class Test{
  public static void main(String[] args){
     B b = new B();
     // 利用匿名內部類 來繼承父類或者實現接口
     b.fun(new A(){
       public vod dosomething(){
         System.out.println("Do domething");
       }
     })
  }
}

Java高級教程