Java的一些基礎補充

謎一樣的Coder發表於2018-06-18

前言

針對Java的一些基礎之前通過簡單例項都有些瞭解,但是一直都沒有在實際應用中加深理解,這次打算通過這個部落格進行一些總結,參考資料來源於《Java核心技術》。這篇部落格只是補充,不會針對其中所有的內容進行詳細描述。

物件與類

靜態域與靜態方法

靜態域與靜態方法都是屬於類級別的,書上沒有介紹實質的內容,只是說了靜態方法和靜態域不能訪問例項域,靜態方法可以訪問靜態域,例項域可以訪問靜態域。這些問題可以聯絡java類中相關的載入順序。

例項如下:

package com.learn.staticArea;

/**
 * Created by liman on 2018/6/17.
 * QQ:657271181
 * e-mail:liman65727@sina.com
 *
 * 這裡用於說明靜態域與靜態方法的一些基本概念
 */
public class StaticTest {
    public static void main(String[] args) {
        Employee[] staff = new Employee[3];

        staff[0] = new Employee("Tom",40000d);
        staff[1] = new Employee("Dick",60000d);
        staff[2] = new Employee("Harry",65000d);

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


}

class Employee{
    private static int nextId = 1;

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

    public Employee(String n ,double s){
        name = n;
        salary = s;
        id = 0;
    }

    public static int getNextId() {
        return nextId;
    }


    public String getName() {
        return name;
    }


    public double getSalary() {
        return salary;
    }

    public void setId() {
        id = nextId;
        nextId++;
    }

    public int getId() {
        return id;
    }

    public static void main(String[] args) {
        Employee e = new Employee("Harry",50000d);
        System.out.println(e.getName()+" "+e.getSalary());
    }
}

方法引數

針對傳值呼叫和引用呼叫進行了說明

一個方法不能修改一個基本資料型別的引數(傳值呼叫)

一個方法可以改變一個物件引數的狀態(針對所引用的物件的操作可以生效)

一個方法不能讓物件引數引用一個新的物件(只針對引用的操作會失效)

package com.learn.methodCall;

/**
 * Created by liman on 2018/6/17.
 * QQ:657271181
 * e-mail:liman65727@sina.com
 *
 * 這個例項針對傳值呼叫和傳引用呼叫進行說明
 */
public class ParamTest {

    public static void main(String[] args) {

        //Test1:Methods can't modify numeric parameters

        System.out.println("Testing tripleValue");
        double percent = 10;
        System.out.println("Before: percent = " + percent); // 輸出10
        tripleValue(percent);
        System.out.println("After: percent = "+percent);    //依舊輸出10,說明是傳值呼叫

        //Test2:Methods can change the state of object parameters
        System.out.println("\nTesting tripleSalary");
        Employee harry = new Employee("Harry",50000);
        System.out.println("Before: salary = "+harry.getSalary());
        tripleSalary(harry);
        System.out.println("After: salary = "+harry.getSalary());

        //Test3: Methods can't attach new objects to object parameters
        System.out.println("\nTesting swap");
        Employee a = new Employee("Alice",70000);
        Employee b = new Employee("Bob",60000);
        System.out.println("Before: a = "+a.getName());
        System.out.println("Before: b = "+b.getName());
        swap(a,b);
        System.out.println("After: a = "+a.getName());
        System.out.println("After: b = "+b.getName());

    }

    public static void tripleValue(double x) { // doesn't work
        x = 3 * x;
        System.out.println("End of method : x = " + x);
    }

    public static void tripleSalary(Employee x) {
        x.raiseSalary(200);
        System.out.println("End of method: x="+x);
    }

    public static void swap(Employee x,Employee y){
        Employee temp = x;
        x = y;
        y = temp;
        System.out.println("End of method:x = "+x.getName());
        System.out.println("End of method:y = "+y.getName());
    }
}

class Employee{
    private String name;

    private double salary;

    public Employee(String n,double s){
        name = n;
        salary = s;
    }

    public String getName() {
        return name;
    }

    public double getSalary() {
        return salary;
    }

    public void raiseSalary(double byPercent){
        double raise = salary*byPercent/10;
        salary+=raise;
    }
}

執行例項(注意第三個例項)

初始化順序

這裡需要總結一下初始化順序:父類靜態程式碼塊->子類靜態程式碼塊->父類非靜態程式碼塊->父類構造方法->子類非靜態程式碼塊->子類構造方法。

package com.learn.construct;

import java.util.Random;

/**
 * Created by liman on 2018/6/18.
 * QQ:657271181
 * e-mail:liman65727@sina.com
 *
 * 針對建構函式相關內容進行說明
 */
public class ConstructorTest {

    public static void main(String[] args) {
        Employee[] staff = new Employee[3];

        staff[0] = new Employee("Harry",40000);
        staff[1] = new Employee(60000);
        staff[2] = new Employee();

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

class Employee{
    private static int nextId;

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

    static{//靜態程式碼塊
        Random genertor = new Random();

        //產生0到9999的隨機數
        nextId = genertor.nextInt(10000);
    }

    {//程式碼塊
        id = nextId;
        nextId++;
    }

    //自定義三個建構函式,會覆蓋掉預設的建構函式
    public Employee(String n ,double s){
        name = n;
        salary = s;
    }

    public Employee(double s){
        this("Employee # "+nextId,s);
    }

    public Employee(){

    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public double getSalary() {
        return salary;
    }
}

上述例項只是列出了一些初始化類中資料的方法,但是沒有針對初始化順序進行詳細的探討。

多型

靜態繫結與動態繫結

針對《Java核心技術 卷1》中針對多型的描述,個人覺得只是介紹了相關概念而已,針對其中的靜態繫結和動態繫結,說明如下:

靜態繫結:如果是private方法,static方法,final方法或者構造器,那麼編譯器將可以準確的知道應該呼叫那個方法,這種呼叫方式成為靜態繫結

動態繫結:程式執行時,虛擬機器會呼叫於指定物件所引用物件的實際型別最合適的那個類的方法。例如:我們需要呼叫X.f(String),假設X的實際型別是D,X是C類的子類。如果D類定義了f(String)方法,則編譯器會直接呼叫D類中的方法,如果D類中沒有定義,則會在D類的超類中尋找f(String)方法。

 

final—阻止繼承

一個類宣告成final,則該類不能被繼承,如果一個方法宣告為final的方法,則該方法不能被複寫。

Object類的相關問題

Object類是所有類的超類,在面試過程中Object的相關問題也是常見的問題,主要集中在其中的equals和hashCode方法中(針對多執行緒相關的內容後期再詳細整理)。

equals方法

object類中equals方法針對物件的判斷是根據引用地址來進行判斷,這只是預設的實現方式,如果需要根據物件的狀態來判斷是否相等,需要複寫equals方法。

hashCode方法

雜湊碼是由物件匯出的一個整形值,針對hashCode的理解只需要補充下一個例項即可

    public static void main(String[] args) {
        String s = "OK";
        StringBuilder sb = new StringBuilder(s);
        System.out.println(s.hashCode()+" "+sb.hashCode());
        String t = new String("OK");    //String 中複寫了hashCode函式,所以t和s的hashCode碼相同
        StringBuilder tb = new StringBuilder(t);
        System.out.println(t.hashCode()+" "+tb.hashCode()); //StringBuilder沒有複寫hashCode,因此兩個hashCode不同
    }

針對hashCode的例項:

 

package com.learn.Object_information;

/**
 * Created by liman on 2018/6/18.
 * QQ:657271181
 * e-mail:liman65727@sina.com
 */
public class EqualsTest {

    public static void main(String[] args) {
        Employee alice1 = new Employee("Alice Adams",75000,1987,12,15);
        Employee alice2 = alice1;
        Employee alice3 = new Employee("Alice Adams",75000,1987,12,15);
        Employee bob = new Employee("Bob Brandson",50000,1989,10,1);

        System.out.println("alice1 == alice2 :" + (alice1 == alice2)); //只是比較地址,true;

        System.out.println("alice1 == alice3 :"+(alice1 == alice3));   //比較地址,false

        System.out.println("alice1.equals(alice3):"+alice1.equals(alice3)); //複寫了equals方法,屬性相同,true

        System.out.println("alice1.equals(bob):"+alice1.equals(bob));//屬性值不同,false

        System.out.println("bob.toString():"+bob);

        Manager carl = new Manager("Carl Cracker",80000,1987,12,15);
        Manager boss = new Manager("Carl Cracker",80000,1987,12,15);
        boss.setBonus(5000);
        System.out.println("boss.toString():"+boss);
        System.out.println("carl.equals(boss):"+carl.equals(boss)); //沒有複寫equals方法,所以為false

        //alice1和alice3的hashCode相同
        System.out.println("alice1.hashCode():"+alice1.hashCode());
        System.out.println("alice3.hashCode():"+alice3.hashCode());

        System.out.println("bob.hashCode():"+bob.hashCode());

        //Carl和boss的hashCode不同
        System.out.println("carl.hashCode():"+carl.hashCode());
        System.out.println("boss.hashCode():"+boss.hashCode());
    }

}

列舉類

列舉這個概念說大不大,說小不小,但是有時候用的好確實能少寫很多程式碼

先上例項程式碼:

package com.learn.enums5_12;

import java.util.Scanner;

/**
 * Created by liman on 2018/7/3.
 * QQ:657271181
 * e-mail:liman65727@sina.com
 */
public class EnumTest {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("Enter a size:(SMALL,MEDIUM,LARGE,EXTRA_LARGE)");
        String input = sc.next().toUpperCase();

        //將size設定成input輸入的值
        Size size = Enum.valueOf(Size.class,input);
        System.out.println("size = "+size);
        System.out.println("abbreviation="+size.getAbbreviation());
        if(size == Size.EXTRA_LARGE){
            System.out.println("Good job--you paid attention to the _.");
        }


        //這裡的toString方法返回的是EXTRA_LARGE
        System.out.println("The extra_large :" + Size.EXTRA_LARGE.toString());
    }
}

enum Size{
    SMALL("S"), MEDIUM("M"), LARGE("L"), EXTRA_LARGE("XL");

    private String abbreviation;

    private Size(String abbreviation){this.abbreviation=abbreviation;}

    public String getAbbreviation(){return abbreviation;}
}

上述例項中需要明確的有以下幾點:

1、所有的列舉型別都是Enum類的子類,它們繼承了Enum類中的一些方法,其中一個是toString,這個方法在這裡返回的是列舉的常量名稱,不是列舉常量對應的值,例如Size.SMALL.toString()返回的是“SMALL”。

2、比較兩個列舉型別的值時,永遠不需要呼叫equals,而是用==

3、列舉中可以有構造方法,構造方法只在構造列舉常量的時候被呼叫。上例中的Enum.valueOf(Size.class,"SMALL")就是將列舉的值設定成Size.SMALL,這個構造方法不同於其他構造方式。

反射

package com.learn.reflect5_13;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Scanner;

/**
 * Created by liman on 2018/7/4.
 * QQ:657271181
 * e-mail:liman65727@sina.com
 */
public class ReflectionTest {

    public static void main(String[] args) {
        //read class name from command line args or user input
        String name;
        if(args.length>0) name = args[0];
        else{
            Scanner in = new Scanner(System.in);
            System.out.println("Enter class name (e.g. java.util.Date):");
            name = in.next();
        }

        try {
            Class cl = Class.forName(name);
            Class superCl = cl.getSuperclass();
            String modifiers = Modifier.toString(cl.getModifiers());
            if(modifiers.length()>0) System.out.println(modifiers + " ");
            System.out.println("Class "+name);
            if(superCl != null && superCl != Object.class) System.out.println(" extends "+superCl.getName());

            System.out.println("\n{\n");

            printConstructors(cl);
            System.out.println();
            printMethod(cl);
            System.out.println();
            printFields(cl);
            System.out.println();
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }
    }


    //獲取構造器的資訊
    public static void printConstructors(Class cl){
        Constructor[] construtors = cl.getConstructors();

        for(Constructor c : construtors){
            String name = c.getName();
            System.out.print("  ");
            String modifiers = Modifier.toString(c.getModifiers());
            if(modifiers.length()>0) System.out.print(modifiers+" ");
            System.out.print(name+"(");

            //print parameter types
            Class[] paramTypes = c.getParameterTypes();
            for(int j =0 ;j<paramTypes.length;j++){
                if(j>0) System.out.print(", ");
                System.out.print(paramTypes[j].getName());
            }

            System.out.println(");");
        }
    }

    public static void printMethod(Class cl){
        Method[] methods = cl.getDeclaredMethods();
        for(Method m : methods){
            Class retType = m.getReturnType();
            String name = m.getName();

            //print modifiers,return type and method name
            System.out.print("  ");
            String modifiers = Modifier.toString(m.getModifiers());
            if(modifiers.length()>0) System.out.print(modifiers+" ");
            System.out.println(retType.getName()+" "+name+"(");

            //print parameter types
            Class[] paramTypes = m.getParameterTypes();
            for(int i = 0;i<paramTypes.length;i++){
                if(i>0) System.out.print(", ");
                System.out.print(paramTypes[i].getName());
            }
            System.out.println(");");
        }
    }

    public static void printFields(Class cl){
        Field[] fields = cl.getDeclaredFields();

        for(Field f: fields){
            Class type = f.getType();
            String name = f.getName();
            System.out.println("   ");
            String modifiers = Modifier.toString(f.getModifiers());
            if(modifiers.length()>0) System.out.print(modifiers+" ");
            System.out.println(type.getName()+" "+name+";");
        }
    }

}

To be continued ......(未完待續......)

 

 

 

相關文章