一、面向对象概念
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 类型的一些方法将其转化为任意基本类型:
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。