Java 学习基础篇 ---- Java面向对象编程

一、面向对象概念

OOP:Object Oriented Programming class和instance是“模版”和“实例”的关系:
类:class,对象模版
实例:instance,具体对象 class用字段(field)封装了数据,不同的instance拥有各自独立的字段(field)
通过变量.字段名访问某个字段(field)
指向instance的变量都是引用变量

二、数据封装

一个 class 可以包含多个 field,直接把 field 用public暴露给外部可能破坏了封装,我们可以用 private关键字 修饰 field 进而拒绝外部访问。
外部代码通过定义 public方法可以间接的修改 private关键字 修饰的 field。
通过 变量.方法名() 来调用实例方法。
通过 方法 访问实例字段更安全。

public class Person{
    private String name;
    private int age;
    public String address;

    public void setName(String name){
        this.name = name;
    }
    public String getName() {
        return this.name; 
    }
}
Person ming = new Person();
ming.address = "北京";     // 可以赋值
ming.name = "小明";  // 编译错误
ming.age = 12;   // 编译错误
ming.setName(" 小明  ");
System.out.println(ming.getName());   // "小明"

(一)方法定义

1、修饰符:public、private、
2、方法返回值:有返回值的方法要写上返回值类型,没有返回值的方法 用void 来表示,void 表示不返回任何值(注意和返回null不同)
3、方法名称:首字母小写,后面的单词首字母大写;
4、方法参数:方法名称后的 () 内写入参数及参数类型列表,如果没有参数则空着,如果有多个参数则需要用逗号隔开每一个参数的类型及变量,方法参数可以是基本类型参数,也可以是引用类型参数。

public class Person{
    private String name;
    private int age;
    public String address;

    public String getName() {
        return this.name; 
    }

    public void setName(String name){
        if (name == null){
            throw new NullPointException();
        }
        this.name = name.trim();
        return;   // 可以省略,因为 void 
    }

    public void retName(String name_1, String name_2){
        // Todo
    }
}

5、方法内部可以使用隐式变量 this,this指向当前实例,this.field 可以访问当前实例的字段。
6、调用方法:实例变量.方法名(参数),可以忽略方法返回值。

Person ming = new Person();
ming.setName("  小明");   // 没有返回值
String s = ming.getName();   // 返回值为 String

7、可以定义 private 方法,外部代码不可以访问 private 方法,内部代码可以调用自己的 private 方法,外部代码可以通过 public 方法间接调用 private 方法。

public class Person{
    private String name;
    private int age;
    public String getBirth() {
        retrun calcBirth(2016);
    }
    private int calcBirth (int currentYear){
        return currentYear - this.age;
    }
}

(二)构造方法

1、构造方法可以在创建对象实例时初始化对象实例
2、构造方法名就是类名
3、构造方法的参数没有限制
4、构造方法没有返回值,也没有 void
5、必须使用 new操作符 调用构造方法

public class Person{
    private String name;
    private int age;
    public Person(String name, int age) {      // 构造方法 Person
        this.name = name;
        this.age = age;
    }
}

6、如果一个类没有定义构造方法,编译器会自动生成一个默认的构造方法(无参数,无执行语句)

public class Person{
    private String name;     // = null
    private int age;            // = 0
    private String address = "北京";
    public Person() {        // 编译器生成的默认构造方法
    }
}

7、如果自定义了构造方法,编译器就不再自动创建默认构造方法
8、 构造方法参数的初始化顺序:先初始化字段,没有赋值的字段初始化为默认值(基本类型=0;引用类型=null),再执行构造方法的代码

public class Person{
    private String name;     // = null
    private int age;            // = 0
    private String address = "北京";
    public Person(String name, int age, Sting address) {       // 三个参数,创建实例时传入
        this.name = name; 
        this.age = age;
        this.address = address;
    }
}

9、一个类的构造方法可以有多个,通过创建实例s时传入的参数个数、参数类型来判断具体调用了哪个构造方法

public class Person{
    private String name;     // = null
    private int age;            // = 0
    private String address = "北京";
    public Person(String name, int age, Sting address) {       // 构造方法一
        this.name = name; 
        this.age = age;
        this.address = address;
    }
    public Person(String name){       // 构造方法二
        this.name = name; 
        System.out.println("hello world")
    }
    public Person(){             // 构造方法三
        System.out.println("hello")
    }
}

10、一个构造方法可以调用其他构造方法,便于代码复用,调用其他构造方法的语法是 this(..)

public class Person{
    private String name;     // = null
    private int age;            // = 0
    private String address = "北京";
    public Person(String name, int age, Sting address) {      // 构造方法一
        this.name = name; 
        this.age = age;
        this.address = address;
    }
    public Person(String name){        // 构造方法二
        this(name,10,"北京")
    }
    public Person(){       // 构造方法三
        this("Andy")
    }
}

(三)方法重载

1、方法重载入是指多个方法的方法名相同,但是各自的参数不同(参数个数,参数类型,参数位置),方法返回值类型通常是相同的。
2、方法重载的目的是使相同功能的方法使用同一方法名,以便于调用

public class Hello {
    public void indexOf (String name){
    }
    public void indexOf (int age){
    }
    public void indexOf (int age, String name){
    }
    public void indexOf (String name, int age){
    }
}
public class Main{
    public static void main(String[] agers){
        Hello s = new Hello();
        int n1 = s. indexOf('t');
        int n2 = s. indexOf('st', 20);
    }
}

三、继承多态

(一)继承

1、继承使用关键字 extends,子类 Student 获得了父类 Person 的所有功能,Student 只需要编写新增的功能。
2、如果定义的类没有写 extends 关键字,则该类继承自 object 类。
3、Java 只允许 class 继承自一个类,不与许同时继承自多个类,即一个类有且仅有一个父类。

public class Person{
    private String name;
    private int age;
    publicString getName(){
        return name
    }
    public void setName(String name){
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void run(){
        System.out.println(name +  " is running!");
    }
}
public class Student extends Person {
    private int score;
    public void setScore(int score){
        return score;
    }
    public int getScore(){
        this.score = score;
    }
}
public class Main{
    public static void main(String[] args){
        Person p = new Person();
        Student s = new Student();
        p.setName("Xiao Ming");
        s.setName("Xiao Hong");
        p.run();     // Xiao Ming is running!
        s.run();     // Xiao Hong is running!
    }
}

4、Person 类定义的 private 字段无法被子类访问
5、Person 类定义的 protected 修饰的字段可以被子类访问。即 protected关键字 把字段和方法的访问权限控制在了继承树内部。

public class Person {
   private String name;
   private int age;
   protected String hight;
   public void run() {
   }
}
public class Student extends Person{
    public String hello(){
        return "Hello," + this. name;             // ERROR!
    }
    public String hello(){
        return "Hello," + this. hight;             // ok
    }
}

6、java 语言规定编写子类的构造方法时,必须在第一行调用父类的构造方法(使用 super() 语句调用),如果没有调用 super() 方法,编译器会默认的帮助我们调用 super() ; 但是如果父类没有默认的构造方法,即父类显式的实现了构造方法,则子类需要在自身的构造方法中显式(手动)调用 super() 方法,并传入父类需要的参数。实例如下:

public class Person {
    public String name;
    public int age;
    public Person(String name){        // 显式的实现带一个参数的构造方法
        System.out.println("create Person");
    }
}
public class Student extends Person{
    public Student(){
        super("小红");         // 父类 Person 是显式构造的构造方法,所以子类 Student 需要显式调用 super(),并传入参数
        System.out.println(" create student");
    }
}

7、向上转型:可以对实例变量进行向上转型(upcasting),向上转型把子类型安全地变为更加抽象的类型。例如 Student 类实例对象 转型为 Person 类实例对象。

Person p = new Person();
Student s = new Student();
Person ps = new Student();    // upcasting   ps 是 Person 类型
Object o1 = p;    // upcasting
Object o2 = s;    // upcasting

8、向下转型:可以对实例变量进行向下转型(downcasting), 向下转型把抽象的类型变成一个具体的子类型。

Person p = new Student()
Student s = (Student) p;   // downcasting 

向下转型很可能报错:ClassCastException

Person p = new Person()
Student s = (Student) p;   // ClassCastException

9、instanceof 操作符:判断实例对象的类型

Person p = new Person();
System.out.println(p instanceof Person);      // true
System.out.println(p instanceof Student);     // false

(二)多态

1、子类覆写父类的方法是覆写(Override),覆写的方法使用 @Override 修饰,该修饰非必须,但是可以让编译器帮助检查是否进行正确的覆写,如下:

public class Person{
    public void run(){
    }
}
public class Student extends Person{
    @Override           // 可省略
    public void run(){
    }
    @Override           // Compile error!  因为没有进行正确覆写
    public void run( String name){
    }
}
Person p = new Student();         
p.run();      

2、方法签名如果不同就不是 Override,而是创建了一个新方法,如下:

public class Person {
    public void run(){
    }
}
public class Student extends Person {         
    public void run(String s){           // 方法签名不同(有参数),所以不是覆写,而是创建了一个新的方法,此处省略了 @Override 关键字
    }
}

3、java 中引用变量的声明类型可能与其实际类型不符
4、多态概念:实例对象的方法调用总是对应实际类型,即Java 的实例方法调用是基于运行时实际类型的动态调用
5、多态定义:指针对某个类型的方法调用,其真正执行的方法取决于运行时实际类型的方法。所以我们对某个类型调用某个方法,执行的方法可能是某个子类的覆写方法。利用多态的允许添加更多类型的子类的特性,实现功能的扩展。

public class Person{
    public void run(String name){
        System.out.println(name + " is running")
    }
}
public class Student extends Person{
    @Override           // 可省略
    public void run(String name){
        System.out.println("Student " + name + " is running")
    }
}
public class Main{
    public static void main(String[] args){
        Person p = new Person("Xiao Ming");
        Person s = new Student(("Xiao Hang");
        p.run();        // 调用的是 Person 类型的 run() 方法
        s.run();      // 调用的是实际类型 Student 的 run() 方法
    }
}

6、所有的类都是从 Object 类继承下来的,是在 Object 类的基础上使用多态实现了功能的扩展。例如:toString() 方法、equals() 方法、hashCode() 方法。

public class Person{              // 在子类 Person 中对父类 Object 的各个方法进行覆写
    @Override
    public String toString(){         // toString() 方法:把接口 instance 输出为 String
    }
    @Override
    public boolean equals(Object o){       // equals() 方法: 判断两个接口 instance 是否逻辑相等
    }
    @Override
    public int hashCode(){    // hashCode() 方法:计算一个接口 instance 的哈希值
    }
}

7、super 方法可以调用父类的被覆写 Override 的方法,如下:

public class Person{
    private String name;
    public String hello(){
        return "Hello, " + name;
    }
}
public Student extends Person{
    @Override
    public String hello(){
        return super.hello() + "!";          // 此处使用 super.hello() 调用父类的 hello() 方法,返回 “Hello,” + name 的执行结果
    }
}

8、 final 关键字:当我们定义一个类的方法时如果不希望该方法被子类覆写,可以使用 final 关键字修饰。
9、使用 final 关键字修饰的类不能被继承;使用 final 关键字修饰的方法不能被Override;使用 final 关键字修饰的字段 field 在初始化后不能被修改;

public class Person{
    public final void setName(String name){
    }
}
public final class Student extends Person{
    private final int score;
}

四、抽象类和接口

(一) 抽象类

1、抽象方法:如果一个class 定义了方法,但没有具体执行代码,这个方法就是抽象方法;
(1)抽象方法使用 abstract 关键字修饰;
(2)抽象方法没有任何执行语句;
(3)因为无法执行抽象方法,因此实现抽象方法的类必须使用 abstract 关键字修饰为抽象类;
(4)抽象类无法实例化,但可以被继承;
(5)抽象类强迫其子类实现其定义的抽象方法,否则编译错误;

public abstract class Person{
    public abstract void run();         // 定义一个抽象方法 run(),和一个抽象类 Person()
}
Person p = new Person();        // 编译错误, 因为抽象类无法实例化
Person s = new Student();       // OK       Student类 继承了 Person类
Person t = new Teacher();       // OK        Teacher类 继承了 Person类
// 调用抽象方法实现多态:
s.run();
t.run();

2、面向抽象编程:
(1)不关心父类 Person类型 对象的具体类型
(2)不关心新的子类是如何实现抽象方法 (run方法)的

public abstract class Person{
    public abstract void run();
}
public class Student extends Person{
    @Override
    public voide run() {
    }
}
public class Teacher extends Person{ 
    @Override
    public void run() {
    }
}
Person s = new Student();
Person t = new Teacher();
s.run()
t.run()

3、总结:
抽象方法定义了子类必须实现的接口规范
定义了抽象方法的类就是抽象类
从抽象类继承的子类必须实现抽象方法
如果不实现抽象方法,则该子类仍是一个抽象类

(二) 接口 --- Interface

1、如果一个抽象类没有字段,所有方法全部是抽象方法,就可以把该抽象类改写为接口(interface),可以使用关键字 interface 来声明一个接口。

public interface Person{
    // public abstract void run();              // 接口定义的方法默认是 public abstract (不需要写)
    void run();
}

2、interface 是 Java 内置的纯抽象接口,实现 interface 使用 implements。

public class Student implements Person{
    @Override
    public void run(){}
}

3、一个类可以同时实现多个 interface。

public class Robot implements Hello, Comparable{
}

4、一个类如果想实现某个接口,子类必须实现该接口中所定义的全部方法,如果接口中方法是使用 default 关键字定义的,则该方法默认被子类实现了

// 接口
public interface Shape{
    double area();              //  继承时 area方法 需要显式实现
    default double perimeter(){              // default 关键字修饰的方法,继承时默认实现
        return 0;
    }
}
// 实现接口的子类
public class Rect implements Shape{
    private final double width;
    private final double height;
    public Rect(double width, double height){
        this.width = width;
        this.height = height;
    }
    @Override
    public double area(){
        return width * height
    }
}
public class Main{
    public static void main(String[] args){
        Shape s1 = new Rect(200, 100);
        System.out.println(s1.area());
    }
}

5、一个 interface 可以继承自另一个 interface,interface 之间的继承使用 extends 关键字

public interface Person {
    String getName();
}
public interface Student extends Person{
    String getSchool();
}
public class PrimaryStudent implements Student{
    @Override
    public String getName(){
    }
    @Override
    public String getSchool(){
    }
}

6、interface 的继承相当于扩展了 interface(接口)的方法

(三) 抽象类 vs 接口

1、合理设计 interface 和 abstract class 的继承关系:公共逻辑放在 abstract class 中。
2、类可以实现多个接口。
3、接口也是数据类型,适用于向上转型和向下转型。
4、接口不能定义实例字段。
5、接口可以定义 default 方法(JDK >= 1.8)

五、包和classpath

(一) 静态字段和静态方法

1、用 static 修饰的字段称为静态字段,普通的字段在每个实例中都有自己的一个独立"空间",静态字段只有一个共享"空间"。
2、对于一个类的所有实例,都共享一个静态字段。
3、不推荐用实例变量访问静态字段。
4、推荐用类名访问静态字段。
5、可以把静态字段理解为描述 class 本身的字段(非实例字段)。

public class Person{
    public String name;
    public int age;
    public static int number = 100;       // 定义一个静态字段 number
}
Person ming = new Person();
Person hong = new Person();
ming.number = 99;            // 通过 实例变量 访问静态字段,不推荐
System.out.println(hong.number);       // 99
Person.number = 88;                     // 使用 类名 调用静态变量 
System.out.println(Person.number);    // 88     

6、用 static 修饰的方法称为静态方法,调用实例方法必须通过实例变量,调用静态方法不需要实例变量,可直接使用类名调用(静态方法类似于其他编程语言中的函数)。

public class Person{
    private String name;
    private static int number = 100;
    pulic static viod setNumber(int num){
        number = num;
    } 
}
Person.setNumber(99);

7、静态方法不能访问 this 变量。
8、静态方法不能访问实例字段。
9、静态方法可以访问静态字段、及其他静态方法。
10、Java程序的入口 main() 也是静态方法。

(二) 包

1、Java 定义了名字空间:包,包名 + 类名 = 完整类名。
2、包(package) 可以是多层结构:java.util.Arrays。
3、包没有父类 / 子类关系:java.util 和 java.util.zip 是不同的包,两者没有任何关系。
4、包作用域:不用 public、protected、private修饰的字段和方法就是包作用域。
5、位于同一个包的类,可以访问包作用域的字段和方法。

package hello;
public class World{
    static int findMax(int[] ns){
    }
}
package hello;
public class Map{
    int price;
    void setPrice(int price)
}

6、包的引用:

package hello;
import java.util.Arrays;

public class World{
    public int findMin(int[] ns){
        Arrays sort(ns);
        return ns[0];
    }
}

(三) 作用域

1、访问权限是指在一个类的内部,能否引用另一个类以及访问它的字段和方法。
2、访问权限有 public、protected、private 和 package 四种。
(1)定义为 public 的 field、method 可以被其他类访问;
(2)定义为 private 的 field、method 无法被其他类访问,但是在类的内部可以访问(即 private 访问权限限定在了 class 的内部);
(3)private 还可以修饰 class,定义为 private 的 class 无法被其他类访问
(4)访问 private class 被限定在外层 class 的内部,定义在一个 class 内部的 class 称为 内部类(inner class)。

package abc;

public class Hello{
    public void hello(){
        Inner inner = null;
    }
    private class Inner{         // 定义一个内部类   Inner
    }
}

(5)protected 作用于继承关系,定义为 protected 的字段和方法可以被子类访问

package abc;

public class Hello{
    protected void hi(){
    }
}
package xyz;

class World extends Hello {
     void foo(){
        Hello h = new Hello();
        h.hi();
    }
}

(6)包作用域(package) 是指一个类允许访问同一个 package 的没有 public、private 修饰的 class,以及没有 public、protected、private 修饰的 字段和方法。注意:包名必须完全一致

package abc;

class Hello {
    void hi() {
    }
}
package abc;

class Main {
    void foo()[
        Hello h = new Hello();
        h.hi()
    }
}

3、最佳实践:最小化暴露对外方法,即尽量少使用 public 。
4、局部变量:在方法内部定义的变量称为局部变量,局部变量作用域由所在语句块{...}决定。

package abc;

public class Hello{
    void hi(String name){
        String s = name.toLowerCase();
        int len = s.length();
        if (len < 10){
           int p = 10 - len;
           for (int i = 0; i < 10; i++){
               System.out.println(i);
           }
        }
    }
}

5、final 关键字:
(1)final 与访问权限不冲突;
(2)用 final 修饰 class 可以阻止被继承;
(3)用 final 修饰 method 可以阻止被覆写;
(4)用 final 修饰 field 可以阻止被重新赋值;
(5)用 final 修饰局部变量可以阻止被重新赋值;

package abc;

public class Hello{
    private int n = 0;
    protected void hi(final int t){
        final long i = t;
    }
}

6、一个.java 文件只能包含一个 public class, 但是可以包含多个非 public class。

(四) classpath 和 jar

1、jar 包是 zip 格式的压缩文件,包含若干 .class 文件。
2、jar 包相当于目录,classpath 可以包含 jar 文件,例如:C:\work\bin\all.jar。
3、查找 com.fiya.Hello 类会在 C:\work\bin\all.jar 文件中搜索 com/fiya/Hello.class。
4、jar 包的其他功能:
(1)jar 包可以包含一个特殊的 /META-INF/MANIFEST.MF 文件,该文件是纯文本,可以指定 Main-Class 和其他信息。
(2)jar 包还可以包含其他 jar 包。
5、JVM运行时会自动加载 JDK 自带的 class。JDK自带的 class 被打包在 rt.jar 中。

六、Java核心类

(一) 字符串和编码

1、String 可以使用 "" 来直接创建,创建后内容不可变。

String s1 = "hello";        // 创建 String 方法一
String s2 = new String("world");        // 创建 String 方法二

2、字符串常用操作:
(1)使用 equals() 判断字符串是否相等,忽略大小写 equalsIgnoreCase(String)

String s = "hello";
s.equals("Hello");    // false
s.equalsIgnoreCase("Hello")     //  true

(2)是否包含字符串:boolean contains(CharSequence)

String s = "hello world";
s.contains("ll");   // true

(3)查找字符串位置:int indexof(String) 和 int lastIndexof(String)

String s = "hello world";
s.indexof("ll");     // 从前向后查找  2
s.lastIndexof("l")      // 从后向前查找  9

(4)是否以指定字符串开头:boolean startsWith(String)

String s = "hello world";
s.startsWith("he");         // true

(5)是否以指定字符串结尾:boolean endsWith(String)

String s = "hello";
s.endsWith("lo");       // true

(6)移除字符串首尾空白字符:trim(),注意 trim() 不改变字符串内容,而是返回新的字符串。

String s = " \t hello \r\n ";
String s2 = s.trim();     // "hello"
s = s.trim();

(7)提取字符串子串:substring()

String s = "hello,world";
s.substring(7);      // "world"
s.substring(1, 5);       // "ello"

(8)大小写转换:toUpperCase()、toLowerCase()

String s = "heLLo";
s.toUpperCase();        // "HELLO"
s.toLowerCase();        // "hello"

(9)替换子串普通替换:replace(char, char)

String s = "hello";
s.replace('l', 'w');      // "hewwo"
s.replace('l', 'w~');     // "hew~w~o"

(10)替换子串正则表达式替换:replaceAll(String,String)

String s = "A,,B;C ,D";
s.replaceAll("[\\,\\;\\s]+", ", ");         // "A, B, C, D"

(11)分割字符串:String[] split(String)

String s = "A,,B;C ,D";
String[] ss = s.split("[\\,\\;\\s]+");           // {"A", "B", "C", "D"}

(12)拼接字符串:static String join()

String[] arr = {"A", "B", "C"};
String s = String.join("~~", arr);          // "A~~B~~C"

3、String 类型和 其他任意类型 的转换
(1)把任意数据转换为 String 类型:static String valuOf(int)、static String valuOf(boolean)、static String valuOf(Object)

String.valueOf(123);     // "123"
String.valueOf(true);     // "true"
String.valueOf(new Object());   // "java.lang.Object@7852e922"

(2)把 String 类型转换为其它类型:
static int Interger.parseInt(String)

int i = Integer.parseInt("123");      //123

static Interger Interger.valueOf(String)

Integer I = Interger.valueOf("123");

4、String 与 char[] 互相转换:
(1)String 转换为 char[]:char[] toCharArray();

String s = "hello";
char[] cs = s.toCharArray();            // {'h', 'e', 'l', 'l', 'o'}

(2)char[] 转换为 String :new String(char[]);

char[] cs = {'h', 'e', 'l', 'l', 'o'};
String s2 = new String(cs);           // "hello"

5、String和byte[]互相转换(需要指定编码)
(1)String 转换为 byte[]: byte[] getBytes(String)、byte[] getBytes(Charset)

String s = "hello";
byte[] bs1 = s.getBytes("UTF-8");
byte[] bs2 = s.getBytes(StandardCharsets.UTF_8);

(2)byte[] 转换为 String: new String(byte[], String)、new String(byte[], Charset)

new String(bs1, "UTF-8");
new String(bs2, StandardCharsets.UTF_8);

6、一个中文字符占用2个字节,中文编码:GB31、GBK、GB8030.
7、全球统一编码:Unicode。Java使用的就是 Unicode 编码。

(二) StringBuidler

1、StringBuilder 是可变对象,可以预分配缓冲区,进而实现高效的拼接字符串。

StringBuilder sb = new StringBuilder(1024);
for (int i = 0; i < 1000; i++){
    sb.append(String.valueOf(i));
}
String s = sb.toString();

2、StringBuilder 可以进行链式操作。

StringBuilder sb = new Stringbuilder(1024);
String s = sb.append("Ms ").append("name").append("!").insert(0, "Hello, ").toString();

3、编译器在内部自动把多个连续的 + 号操作优化为 StringBuilder 操作。

String s = "Hello, " + "nemw" + "!";

4、Java 还提供了一个和 StringBuilder 接口完全相同的接口 StringBuffer,StringBuffer 是线程安全的,一般没必要使用。

(三) 包装类型

1、Java 的属性包括 基本数据类型 和 引用数据类型,基本类型不能视为对象,如果我们把一个基本类型赋值为null ,程序会报错。

int n = null;     // ERROR!   

2、可以对基本类型进行包装,变成一个引用类型(即包装类型实际上是一个引用类型,只不过其内部包含一个基本类型的变量)。

// 定义一个 Integer 类,包含一个实例字段 int
public class Integer {
    private int value;
    public Integer(int value) {
        this.value = value;
    }
}
Integer n = null;
Integer n2 = new Integer(99);

以上是我们手动实现的包装类型,其实 JDK 已经为每种基本类型都创建了对应的包装类型,无需我们手动实现:

基本类型                对应的引用类型
boolean                  Boolean
byte                        Byte
short                      Short
int                          Integer
long                       Long
float                      Float
double                  Double
char                      Character

3、基本类型int 和 对应的引用类型Integer 可以相互转化:

Integer n = new Integer(99);           // 基本类型 转换为 引用类型
int i = n.intValue();                 // 引用类型 转换为 基本类型
Integer n1 = Interger.valueOf("88");      // String类型 转换为 引用类型Interger
String s = n.toString();          // 引用类型Interger   转换为   String类型

特别注意 Integer.getInteger(String) 是从系统环境中读取系统变量。
4、编译器可以自动在 int 和 Integer 之间转型:自动装箱、自动拆箱

Integer n = 99;            // Integer.valueOf(99)        自动装箱 int -> Integer
int i = n;          // n.intValue()          自动拆箱 Integer -> int

注意:自动装箱和自动拆箱只发生在编译阶段;
装箱和拆箱会影响执行效率;
编译后的class代码是严格区分基本类型和引用类型的;
自动拆箱时:Integer -> int 执行时可能会报错(null 时),即 Integer x = null; int y = x; // NullPointerException
5、Java 的包装类型定义了一些有用的静态变量

Boolean t = Boolean.TRUE;
Boolean f = Boolean.FALSE;
int max = Integer.MAX_VALUE;       // 2147483647
int min = Integer.MIN_VALUE;       // -2147483647
int sizeOfLong = Long.SIZE;        // 64 (bite)
int bytesOfLong = Long.BYTES;       // 8(bytes)

6、整数和浮点数包装类型继承自 Number,所以我们可以对这些包装类型进行向上转型(变为 Number 类型),然后使用 Number 类型的一些方法将其转化为任意基本类型:


Java 学习基础篇 ---- Java面向对象编程_第1张图片
继承关系.png
Number num = new Integer(999)         // 将包装类型 Integer 向上转型为 Number 类型
byte b = num.byteValue();
int n = num.intValue();
long ln = num.longValue();
float f = num.floatValue();
double d = num.doubleValue();

(四) JavaBean

1、许多 class 的定义都符合:a.若干 private 实例字段、b.通过 public 方法读写实例字段。符合以上两种命名规范的 class 被称为 JavaBean,即:
(1)private Type field
(2)public Type getField()
(3)public void setField(Type value)
注意:以上三点中方法名称大小写不能改变。

public class Person{
    private String name;
    private int age;

    public String getName(){
    }
    public void setName(String name){
    }

    public int getAge(){
    }
    public void setAge(int age){
    }
}

boolean 字段的读方法命名为 isXxx():

private boolean child
public boolean isChild() {}     // 读方法
public void setChild(boolean value){}

2、通常把一组对应的 getter 和 setter 方法称为属性(Property):
(1) 读写属性都具备:
name 属性:
有对应读方法 getName()
有对应写方法 setName()

(2) 只有 setter 的属性称为只写属性(Write-only):
age 属性:
无对应读方法 getAge()
有对应写方法 setAge()

(3) 只有 getter 的属性称为只读属性(Read-only):
age 属性:
有对应读方法 getAge()
无对应写方法 setAge()

(五) 枚举类型

1、常量的定义
(1)可以使用 enum 关键字定义常量, 使用 enum 关键字定义的常量本身带有类型,使用 == 比较常量是否相等。
(2)enum 可以定义常量类型,它被编译器编译为:final class Xxx extends Enum{...}

public enum Weekday{                // 定义了一些 Weekday 类型的常量
    SUN, MON, TUE, WED;
}
public enum Color {          // 定义了一些 Color 类的常量
    RED, GREEN, BLUE;
}
if (day == Weekday.FRI){
}

enum 定义的类型实际上是 class,继承自 java.lang.Enum(如下),不能通过 new 创建实例,所有常量都是唯一实例,可以用于 switch 语句

public enum Color{
    RED, GREEN, BLUE;
}
// 编译器编译出来的 class:
import java.lang.Enum
public final class Color extends Enum{
    public static final Color RED = new Color();
    public static final Color GREEN = new Color();
    public static final Color BLUE = new Color();
    private Color(){}
}

2、常量的一些使用:
(1)name() 获取常量定义的字符串,注意不要使用 toString()
(2)ordinal() 返回常量定义的顺序(无实质意义)

package com.test;
public enum Weekday {
    SUN, MON, TUE, WED, THU, FRI, SAT;
}
package com.test;
public class Main{
    public static void main(String[] args){
        for (Weekday day : Weekday.values()){
            System.out.println(day.name());
        }
        Weekday fri = Weekday.FRI;      // 将常量 FRI 赋值给 fri
        System.out.println(fri.name());       // enum类型 -> String类型
        System.out.println(fri.ordinal());      // 返回常量定义的顺序
        System.out.println(Weekday.valueOf("FRI").name());      // String类型 —> enum类型
        Weekday.valueOf("ABC");           // 不存在的常量,会抛出 IllegalArgumentException
    } 
}

(3)构造方法申明为 private
(4)可以为enum枚举类编写构造方法、字段和方法,例如为每个枚举类型添加一个中文名称:

package com.test;
public enum Weekday {
    // b. 传入构造方法的参数,继而调用构造方法
    SUN("星期日"), MON("星期一"), TUE("星期二"), WED("星期三"), THU("星期四"), FRI("星期五"), SAT("星期六");        
    private String chinese;
    private Weekday(String chin){         // a. 使用构造方法 初始化 chinese 
        this.chinese = chin;
    }
    public String toChinese() {         // c. 定义 toChinese 方法返回  chinese
        return chinese
    }
}
public class Main{
    public static void main(String[] args){
        Weekday fri = Weekday.FRI;
        System.out.println(fri.toChinese());           // 星期五
    }
}

(六) 常用工具类

1、Math 类:提供类数学计算的静态方法:
(1)abc / min / max
(2)pow / sqrt / exp / log / log10
(3)sin / cos / tan / asin / acos
(4)常量:PI = 3.14159;E = 2.71828
(5)Math.random() 生成一个随机数,范围 0 <= 随机数 < 1

double x1 = Math.random();
long MIN = 1000;
long MAX = 9000;
double x2 = Math.random() * (MAX - MIN) + MIN;
double r = (long) x2;

(6)Random 对象:Random 对象用来创建伪随机数

Random r = new Random();
r.nextInt();       // 生成下一个随机 int
r.nextLong();    // 生成下一个随机 long
r.nextFloat();    // 生成下一个随机 float,介于 0~1
r.nextDouble();    // 生成下一个随机 double,介于 0~1
r.nextInt(10);     // 生成 0~10 之间的随机数,不包括 10

(7)为随机数:给定种子后伪随机数算法会生成完全相同的序列,不给定种子时 Random 使用系统当前时间戳作为种子。

Random r = new Random(12345);
for (int i = 0; i < 10; i ++){
    System.out.println(r.nextInt(100))
}

2、SecureRandom:生成安全的随机数。
3、BigInteger:表示任意大小的整数。
4、BigDecimal:表示任意精度的浮点数。
5、BigInteger 和 BigDecimal 都继承自 Number。

你可能感兴趣的:(Java 学习基础篇 ---- Java面向对象编程)