Java 菜鳥教程學習筆記

目錄

修飾符

訪問控制和繼承

Protected可見性

邏輯運算符&&

增強for循環(for-each循環)

switch - case 開關結構

裝箱、拆箱

Math 的 floor,round 和 ceil 方法實例比較

String類不可修改

測量時間

值傳遞與引用傳遞

方法的重載

構造方法

可變參數

控制檯讀取與輸出

控制檯讀取

控制檯輸出

讀寫文件


修飾符

Java語言提供了很多修飾符,主要分爲以下兩類:

  • 訪問修飾符
  • 非訪問修飾符

Java中,可以使用訪問控制符來保護對類、變量、方法和構造方法的訪問。Java 支持 4 種不同的訪問權限。

  • default (即默認,什麼也不寫): 在同一包內可見,不使用任何修飾符。使用對象:類、接口、變量、方法。

  • private : 在同一類內可見。使用對象:變量、方法。 注意:不能修飾類(外部類)

  • public : 對所有類可見。使用對象:類、接口、變量、方法

  • protected : 對同一包內的類和所有子類可見。使用對象:變量、方法。 注意:不能修飾類(外部類)

訪問控制和繼承

請注意以下方法繼承的規則:

  • 父類中聲明爲 public 的方法在子類中也必須爲 public。

  • 父類中聲明爲 protected 的方法在子類中要麼聲明爲 protected,要麼聲明爲 public,不能聲明爲 private。

  • 父類中聲明爲 private 的方法,不能夠被繼承。

Protected可見性

protected的可見性在於兩點:

  • 基類的 protected 成員是包內可見的,並且對子類可見;
  • 若子類與基類不在同一包中,那麼在子類中,子類實例可以訪問其從基類繼承而來的protected方法,而不能訪問基類實例的protected方法。
例1:
=============================================================
package p1;
public class Father1 {
    protected void f() {}    // 父類Father1中的protected方法
}
 
package p1;
public class Son1 extends Father1 {}
 
package p11;
public class Son11 extends Father1{}
 
package p1;
public class Test1 {
    public static void main(String[] args) {
        Son1 son1 = new Son1();
        son1.f(); // Compile OK     ----(1)
        son1.clone(); // Compile Error     ----(2)
 
        Son11 son = new Son11();    
        son11.f(); // Compile OK     ----(3)
        son11.clone(); // Compile Error     ----(4)
    }
}

對於上面的示例,首先看(1)(3),其中的f()方法從類Father1繼承而來,其可見性是包p1及其子類Son1和Son11,而由於調用f()方法的類Test1所在的包也是p1,因此(1)(3)處編譯通過。其次看(2)(4),其中的clone()方法的可見性是java.lang包及其所有子類,對於語句"son1.clone();"和"son11.clone();",二者的clone()在類Son1、Son11中是可見的,但對Test1是不可見的,因此(2)(4)處編譯不通過。

例2:
=================================================================
package p2;
class MyObject2 {
    protected Object clone() throws CloneNotSupportedException{
       return super.clone();
    }
}
 
package p22;
public class Test2 extends MyObject2 {
    public static void main(String args[]) {
       MyObject2 obj = new MyObject2();
       obj.clone(); // Compile Error         ----(1)
 
       Test2 tobj = new Test2();
       tobj.clone(); // Complie OK         ----(2)
    }
}

對於(1)而言,clone()方法來自於類MyObject2本身,因此其可見性爲包p2及MyObject2的子類,雖然Test2是MyObject2的子類,但在Test2中不能訪問基類MyObject2的protected方法clone(),因此編譯不通過;對於(2)而言,由於在Test2中訪問的是其本身實例的從基類MyObject2繼承來的的clone(),因此編譯通過。

例3:
================================================
package p3;
class MyObject3 extends Test3 {
}
 
package p33;
public class Test3 {
  public static void main(String args[]) {
    MyObject3 obj = new MyObject3();
    obj.clone();   // Compile OK     ------(1)
  }
}

對於(1)而言,clone()方法來自於類Test3,因此其可見性爲包p33及其子類MyObject3,而(1)正是在p33的類Test3中調用,屬於同一包,編譯通過。

例4:
===============================================================
package p4;
class MyObject4 extends Test4 {
  protected Object clone() throws CloneNotSupportedException {
    return super.clone();
  }
}
 
package p44;
public class Test4 {
  public static void main(String args[]) {
    MyObject4 obj = new MyObject4();
    obj.clone(); // Compile Error      -----(1)
  }
}

對於(1)而言,clone()方法來自於類MyObject4,因此其可見性爲包p4及其子類(此處沒有子類),而類Test4卻在包p44中,因此不滿足可見性,編譯不通過。

例5:
================================================================================
package p5;
 
class MyObject5 {
    protected Object clone() throws CloneNotSupportedException{
       return super.clone();
    }
}
public class Test5 {
    public static void main(String[] args) throws CloneNotSupportedException {
       MyObject5 obj = new MyObject5();
       obj.clone(); // Compile OK        ----(1)
    }
}

對於(1)而言,clone()方法來自於類MyObject5,因此其可見性爲包p5及其子類(此處沒有子類),而類Test5也在包p5中,因此滿足可見性,編譯通過。

例6:
=====================================================
package p6;
 
class MyObject6 extends Test6{}
public class Test6 {
  public static void main(String[] args) {
    MyObject6 obj = new MyObject6();
    obj.clone();        // Compile OK   -------(1)
  }
}

對於(1)而言,clone()方法來自於類Test6,因此其可見性爲包p6及其子類MyObject6,而類Test6也在包p6中,因此滿足可見性,編譯通過。

例7:==================================================
=
package p7;
 
class MyObject7 extends Test7 {
    public static void main(String[] args) {
        Test7 test = new Test7();
        test.clone(); // Compile Error   ----- (1)
  }
}
 
public class Test7 {
}

對於(1)而言,clone()方法來自於類Object,因此該clone()方法可見性爲包java.lang及其子類Test7,由於類MyObject7不在此範圍內,因此不滿足可見性,編譯不通過。

邏輯運算符&&

當使用與邏輯運算符&&時,在兩個操作數都爲true時,結果才爲true,但是當得到第一個操作爲false時,其結果就必定是false,這時候就不會再判斷第二個操作了。

public class LuoJi{
    public static void main(String[] args){
        int a = 5;//定義一個變量;
        boolean b = (a<4)&&(a++<10);
        System.out.println("使用邏輯與運算符的結果爲"+b);
        System.out.println("a的結果爲"+a);
    }
}
=========================================================
使用邏輯與運算符的結果爲false
a的結果爲5

解析: 該程序使用到了短路邏輯運算符(&&),首先判斷 a<4 的結果爲 false,則 b 的結果必定是 false,所以不再執行第二個操作 a++<10 的判斷,所以 a 的值爲 5。

增強for循環(for-each循環)

主要用於數組,能在不使用下標的情況下遍歷數組

for(聲明語句 : 表達式)
{
   //代碼句子
}
  • 聲明語句:聲明新的局部變量,該變量的類型必須和數組元素的類型匹配。其作用域限定在循環語句塊,其值與此時數組元素的值相等。
  • 表達式:表達式是要訪問的數組名,或者是返回值爲數組的方法。
public class Test {
   public static void main(String args[]){
      int [] numbers = {10, 20, 30, 40, 50};
 
      for(int x : numbers ){
         System.out.print( x );
         System.out.print(",");
      }
      System.out.print("\n");
      String [] names ={"James", "Larry", "Tom", "Lacy"};
      for( String name : names ) {
         System.out.print( name );
         System.out.print(",");
      }
   }
}
===============================================================
10,20,30,40,50,
James,Larry,Tom,Lacy,

switch - case 開關結構

switch case 執行時,一定會先進行匹配,如果沒有匹配項,則不執行指令;如果匹配成功則返回當前 case 的值,再根據是否有 break,若有break,直接跳出switch結構,若無break,從當前 case 開始,後續所有 case 的值都會輸出,無論是否匹配。

public class Test {
   public static void main(String args[]){
      int i = 1;
      switch(i){
         case 0:
            System.out.println("0");
         case 1:
            System.out.println("1");
         case 2:
            System.out.println("2");
         default:
            System.out.println("default");
      }
   }
}
=============================================
1
2
default

裝箱、拆箱

(這裏沒有弄明白)

在實際開發過程中,我們經常會遇到需要使用對象,而不是內置數據類型的情形。爲了解決這個問題,Java 語言爲每一個內置數據類型提供了對應的包裝類。所有的包裝類(Integer、Long、Byte、Double、Float、Short)都是抽象類 Number 的子類。

這種由編譯器特別支持的包裝稱爲裝箱,所以當內置數據類型被當作對象使用的時候,編譯器會把內置類型裝箱爲包裝類。相似的,編譯器也可以把一個對象拆箱爲內置類型。Number 類屬於 java.lang 包。

public class Test{
 
   public static void main(String args[]){
      Integer x = 5;  //當 x 被賦爲整型值時,由於x是一個對象,所以編譯器要對x進行裝箱
      x =  x + 10;    //爲了使x能進行加運算,所以要對x進行拆箱。
      System.out.println(x); 
   }
}
==============================================
15

Math 的 floor,round 和 ceil 方法實例比較

  • floor() :返回小於等於(<=)給定參數的最大整數 。
  • round() : 它表示四捨五入,算法爲 Math.floor(x+0.5),即將原來的數字加上 0.5 後再向下取整。所以Math.round(11.5) 的結果爲12,Math.round(-11.5) 的結果爲-11
  • ceil() : 返回大於等於( >= )給定參數的的最小整數,類型爲雙精度浮點型

String類不可修改

String 類是不可改變的,所以你一旦創建了 String 對象,那它的值就無法改變了。如果需要對字符串做很多修改,那麼應該選擇使用 StringBuffer 和 StringBuilder類,StringBuffer 和 StringBuilder 類的對象能夠被多次的修改,並且不產生新的未使用對象。

StringBuilder 類在 Java 5 中被提出,它和 StringBuffer 之間的最大不同在於 StringBuilder 的方法不是線程安全的(不能同步訪問)。由於 StringBuilder 相較於 StringBuffer 有速度優勢,所以多數情況下建議使用 StringBuilder 類。然而在應用程序要求線程安全的情況下,則必須使用 StringBuffer 類。

String s = "Google";
System.out.println("s = " + s);

s = "Runoob";
System.out.println("s = " + s);
===================================
Google
Runoob

從結果上看是改變了,但爲什麼說String對象是不可變的呢?

原因在於實例中的 s 只是一個 String 對象的引用,並不是對象本身,當執行 s = "Runoob"; 創建了一個新的對象 "Runoob",而原來的 "Google" 還存在於內存中。

測量時間

import java.util.*;
  
public class DiffDemo {
 
   public static void main(String args[]) {
      try {
         long start = System.currentTimeMillis( );
         System.out.println(new Date( ) + "\n");
         Thread.sleep(5*60*10);
         System.out.println(new Date( ) + "\n");
         long end = System.currentTimeMillis( );
         long diff = end - start;
         System.out.println("Difference is : " + diff);
      } catch (Exception e) {
         System.out.println("Got an exception!");
      }
   }
}

System.out.println():調用系統類 System 中的標準輸出對象 out 中的方法 println()

值傳遞與引用傳遞

  • 值傳遞:按值的拷貝傳遞,即傳遞後互不相關,java中原始數據類型均爲按值傳遞
  • 引用傳遞:傳遞的引用的地址,傳遞前後變量只想同一個引用(即同一個內存空間,引用又叫起別名),非原始數據類型即引用數據類型是引用傳遞

方法的重載

函數名相同,參數列表不同(類型或個數等),java編譯器根據參數判斷調用哪一個函數。重載的方法必須擁有不同的參數列表。不能僅僅依據修飾符或者返回類型的不同來重載方法。

構造方法

  • 每個類都有構造方法,當一個對象被創建時候,構造方法用來初始化該對象。
  • 構造方法若無顯示定義,java編譯器提供默認構造方法,其訪問修飾符與類相同。
  • 構造方法沒有返回值。
  • 一個類可以有多個構造方法,名稱必須與類名相同

可變參數

JDK 1.5 開始,Java支持傳遞同類型的可變參數給一個方法。

方法的可變參數的聲明如下所示:

typeName... parameterName

在方法聲明中,在指定參數類型後加一個省略號(...) 。

一個方法中只能指定一個可變參數,它必須是方法的最後一個參數。任何普通的參數必須在它之前聲明。

public class VarargsDemo {
    public static void main(String args[]) {
        // 調用可變參數的方法
        printMax(34, 3, 3, 2, 56.5);
        printMax(new double[]{1, 2, 3});
    }
 
    public static void printMax( double... numbers) {
        if (numbers.length == 0) {
            System.out.println("No argument passed");
            return;
        }
 
        double result = numbers[0];
 
        for (int i = 1; i <  numbers.length; i++){
            if (numbers[i] >  result) {
                result = numbers[i];
            }
        }
        System.out.println("The max value is " + result);
    }
}
============================================================
The max value is 56.5
The max value is 3.0

控制檯讀取與輸出

控制檯讀取

Java 的控制檯輸入由 System.in 完成。爲了獲得一個綁定到控制檯的字符流,你可以把 System.in 包裝在一個 BufferedReader 對象中來創建一個字符流。

下面是創建 BufferedReader 的基本語法:

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

BufferedReader 對象創建後,便可以使用 read() 方法從控制檯讀取一個字符,或者用 readLine() 方法讀取一個字符串。

  • int read( ) throws IOException : 讀取字符,每次調用 read() 方法,它從輸入流讀取一個字符並把該字符作爲整數值返回。 當流結束的時候返回 -1。該方法拋出 IOException。
  • String readLine( ) throws IOException : 讀取字符串
//使用 BufferedReader 在控制檯讀取字符 
import java.io.*;
 
public class BRRead {
    public static void main(String args[]) throws IOException {
        char c;
        // 使用 System.in 創建 BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("輸入字符, 按下 'q' 鍵退出。");
        // 讀取字符
        do {
            c = (char) br.read();
            System.out.println(c);
        } while (c != 'q');
    }
}
=================================================================================
將輸入的字符分行單個輸出,直至輸入q,程序終止
//使用 BufferedReader 在控制檯讀取字符
import java.io.*;
 
public class BRReadLines {
    public static void main(String args[]) throws IOException {
        // 使用 System.in 創建 BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str;
        System.out.println("Enter lines of text.");
        System.out.println("Enter 'end' to quit.");
        do {
            str = br.readLine();
            System.out.println(str);
        } while (!str.equals("end"));
    }
}
========================================================================================
輸出讀取到的字符串

控制檯輸出

控制檯的輸出由 print( ) 和 println() 完成。這些方法都由類 PrintStream 定義,System.out 是該類對象的一個引用。

PrintStream 繼承了 OutputStream類,並且實現了方法 write()。這樣,write() 也可以用來往控制檯寫操作。但不常使用。

void write(int byteval)

讀寫文件

FileInputStream

該流用於從文件讀取數據,它的對象可以用關鍵字 new 來創建。

可以使用字符串類型的文件名來創建一個輸入流對象來讀取文件:

InputStream f = new FileInputStream("C:/java/hello");

也可以使用一個文件對象來創建一個輸入流對象來讀取文件。我們首先得使用 File() 方法來創建一個文件對象:

File f = new File("C:/java/hello"); InputStream out = new FileInputStream(f);

FileOutputStream

該類用來創建一個文件並向文件中寫數據。如果該流在打開文件進行輸出前,目標文件不存在,那麼該流會創建該文件。

使用字符串類型的文件名來創建一個輸出流對象:

OutputStream f = new FileOutputStream("C:/java/hello")

也可以使用一個文件對象來創建一個輸出流來寫文件。我們首先得使用File()方法來創建一個文件對象:

File f = new File("C:/java/hello"); OutputStream f = new FileOutputStream(f);
//文件名 :fileStreamTest2.java
import java.io.*;
 
public class fileStreamTest2 {
    public static void main(String[] args) throws IOException {
 
        File f = new File("a.txt");
        FileOutputStream fop = new FileOutputStream(f);
        // 構建FileOutputStream對象,文件不存在會自動新建
 
        OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8");
        // 構建OutputStreamWriter對象,參數可以指定編碼,默認爲操作系統默認編碼,windows上是gbk
 
        writer.append("中文輸入");
        // 寫入到緩衝區
 
        writer.append("\r\n");
        // 換行
 
        writer.append("English");
        // 刷新緩存衝,寫入到文件,如果下面已經沒有寫入的內容了,直接close也會寫入
 
        writer.close();
        // 關閉寫入流,同時會把緩衝區內容寫入文件,所以上面的註釋掉
 
        fop.close();
        // 關閉輸出流,釋放系統資源
 
        FileInputStream fip = new FileInputStream(f);
        // 構建FileInputStream對象
 
        InputStreamReader reader = new InputStreamReader(fip, "UTF-8");
        // 構建InputStreamReader對象,編碼與寫入相同
 
        StringBuffer sb = new StringBuffer();
        while (reader.ready()) {
            sb.append((char) reader.read());
            // 轉成char加到StringBuffer對象中
        }
        System.out.println(sb.toString());
        reader.close();
        // 關閉讀取流
 
        fip.close();
        // 關閉輸入流,釋放系統資源
 
    }
}

 

參考:

https://www.runoob.com/java/java-operators.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章