Java的一些基础补充

前言

针对Java的一些基础之前通过简单实例都有些了解,但是一直都没有在实际应用中加深理解,这次打算通过这个博客进行一些总结,参考资料来源于《Java核心技术》。这篇博客只是补充,不会针对其中所有的内容进行详细描述。

对象与类

静态域与静态方法

静态域与静态方法都是属于类级别的,书上没有介绍实质的内容,只是说了静态方法和静态域不能访问实例域,静态方法可以访问静态域,实例域可以访问静态域。这些问题可以联系java类中相关的加载顺序。

实例如下:

package com.learn.staticArea;

/**
 * Created by liman on 2018/6/17.
 * QQ:657271181
 * e-mail:[email protected]
 *
 * 这里用于说明静态域与静态方法的一些基本概念
 */
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:[email protected]
 *
 * 这个实例针对传值调用和传引用调用进行说明
 */
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:[email protected]
 *
 * 针对构造函数相关内容进行说明
 */
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:[email protected]
 */
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:[email protected]
 */
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,这个构造方法不同于其他构造方式。

猜你喜欢

转载自blog.csdn.net/liman65727/article/details/80722888