Java基础类库

面向对象的核心—类和对象

  1. 类的语法定义
    • 类的修饰符
      • static可以修饰变量和方法,称为类变量、类方法,它们属于类本身。不被static修饰的变量和方法称为实例变量、实例方法,属于类的实例。
      • 在类准备阶段,系统就为类变量分配内存空间,类初始化阶段完成类变量的初始化。类变量可以通过类来访问,也可以通过类的对象来访问(其实系统在底层转换成通过该类访问类变量,并不会为类变量分配内存),类方法也是。
      • 类成员的作用域比实例成员的作用域更大,可能类成员初始化完成而实例成员未初始化完成,为避免错误,类成员不能访问实例成员。
[public/final/abstract] class Name{
        //构造器
        [public/private/protected] Name(struct val){
        }    
        //成员变量
        [public/protected/private/static/final] type tname [= defualt];
        //方法
        [public/protected/private/static/final/abstract] type set/get(struct val){
        }
}
- 类名
- 成员变量
    类的成员变量分为类变量和实例变量,类变量与类共存亡,实例变量与对象共存亡。
- 局部变量
    局部变量分为形参、方法局部变量和代码块局部变量,除了形参之外的局部变量声明后必须显式初始化才能使用(系统不会默认初始化局部变量)。局部变量保存基本类型的值或者对象的引用,存放在栈内存中,随着方法或代码块的结束而消亡。
- 构造器
    - 构造器名与类名相同,不能显式指定返回值(隐式返回当前类)。没有显式提供构造器时调用系统默认构造器,即Java至少有一个构造器。
    - 创建对象的根本途径就是使用new关键字调用类的构造器。
        `Person p = new Person();`
        p是一个引用变量,只存储一个地址值,Java程序不允许直接访问堆内存中的对象,只能通过对象的引用来访问。`创建对象`的过程如下:
        - 调用构造器
        - 类准备阶段--系统为对象分配内存空间
        - 类初始化阶段--执行初始化块,执行默认初始化
        - 通过this引用执行构造器内的程序体,进行显式初始化
        - 返回该对象
    - 构造器重载
        如果一个构造器包含另一个构造器,则可以使用this来调用另一个构造器,方便以后的修改,降低维护成本。
- 初始化块
    如果多个构造器中有相同的初始化代码,则可以把它们放到普通初始化块里完成。初始化块总在构造器执行之前执行。static{}静态初始化块初始化类。
- 方法
    - Java的方法只能属于类本身或者类的对象,不能独立存在。
     - Java方法只能使用值传递。如果参数是基本类型的值,则会开辟新的栈内存存放临时变量;如果参数是引用类型的值,也会开辟新的栈内存存放引用变量,但是变量都是指向堆内存的同一对象。
    - 参数为数组时可以采用形参个数可变的方法,进而使用foreach循环。
        `public void exmple(int a, String... strings){}`
    - 方法重载
    同一个类相同方法名,参数列表不同即为重载,和其他项无关。
  1. 类的作用
    • 定义变量
    • 创建类的对象
    • 调用类的方法或访问类的变量
  2. this引用
    this关键字总是指向调用该方法的对象。
    • 构造器中引用正在初始化的对象
public Person(int age){
    this.age = age;
}
- 普通方法中引用调用该方法的对象(可省略this关键字)
    谁调用set()方法,this代表谁。
public void get(){
}
    pubilc void set(){
        this.get();
    }
- static修饰的方法不能使用this引用,因为如果使用this,则this无法指向合适的对象

抽象类

抽象类作为一种模板,提供通用的方法,是一种更高层次的抽象。

  1. 抽象方法只有方法签名,没有方法实现。有抽象方法的类只能被定义为抽象类,而抽象类里可以没有抽象方法。抽象类和抽象方法都用abstract修饰。抽象方法和空方法不同。
    public abstract void test();
  2. 抽象类的构造器不能创建实例,仅用于子类调用,子类必须重写抽象方法。所以final、private和abstract不能同时使用,static和abstract不能同时修饰方法,可同时修饰内部类。

接口

接口作为特殊的抽象类,是一种规范,其不提供任何方法实现。所有方法都是抽象方法,Java8允许定义默认方法(default修饰,可以提供实现)。

  1. 接口使用interface关键字定义。
  2. 接口只能继承接口,可以有多个父接口。
  3. 接口只能包含静态常量(pubilc static final修饰+指定默认值),只能有抽象方法(默认public abstract,普通方法不能有方法实现,类方法和默认方法必须实现),只能定义内部类/接口/枚举(默认public static)。
  4. 访问控制符只能使用public或者省略。
  5. 一个类可以实现多个接口,关键字用implements,放在extends后面。
  6. 实现类必须重写接口所有的抽象方法,必须用public修饰。

比较抽象类和接口

Java8增强的包装类

  1. 为了将八种基本数据类型变成引用类型,继承Object类,Java提供了包装类,对应关系如下:
    • byte - Byte
    • short - Short
    • int - Integer
    • long - Long
    • char - Character
    • float - Float
    • double - Double
    • boolean - Boolean
  2. 自动装箱和自动拆箱
    可以直接将一个基本类型的变量赋值给对应的包装类变量,或者赋值给Object变量,自动拆箱则相反。
  3. 字符串转换成基本类型的值
    • 利用除Character类的包装类提供的静态方法
      int it1 = Integer.parseInt("12345");
    • 利用包装类提供的构造器
      float ft1 = new Float("12345");
  4. 基本类型的值转换成字符串
    • 利用连接符+
      String str1 = 10 + "";
    • 利用String类重载的valueOf()方法
      String str2 = String.valueOf(true);
  5. 包装类的实例可以与基本数据类型的值进行比较
  6. 自动装箱缓存问题(见java.lang.Integer类的源代码)
    将-128~127之间的整数自动装箱成Integer实例时,永远都是引用cache数组中的同一个数组元素,而在范围之外的值自动装箱时,总是会创建新的Integer实例,不相同。

Object类

Java所有的类默认继承Object父类,因此所有的类都可调用父类的方法。

  1. 重写toSpring()方法输出类的对象的状态信息
    public String toString(){
            return "success";
    }
    
  2. ==和equals方法
    • 运算符
      如果两个数值类型(不一定数据类型严格对应)相等则返回true;如果两个引用变量指向同一对象则返回true,
      不能比较非父子关系的两个对象。
    • 关于常量池
      在编译时被确定并保存在.class文件中的字符串常量和类、接口、方法中的常量保存在常量池中。常量池中的常量是唯一的。new Integer(12)实际上定义了两个对象。
class EqualTest{
	        public void compare() {
		        String str1 = "123";
		        String str2 = "123";
		        String str3 = new String("123");
		        String str4 = new String("123");
		
		        System.out.println(str1 == str2);
		        System.out.println(str1 == str3);
		        System.out.println(str3 == str4);
		
		        System.out.println(str1.equals(str2));
		        System.out.println(str1.equals(str3));
		        System.out.println(str3.equals(str4));
	        }
}

输出true、false、false;true、true、true。
- equals方法
- 如果两个对象的值相等则返回true。
- String已经重写了equals方法,对于其他的Object类equals方法等同于==(都是比较对象的地址),如果想自定义可以重写equals方法。
- equals方法的前一个变量不能为null,如"123".equals(str)

public class Test {
	String id = "213";
	public String getId() {
		return id;
	}
	
	public boolean equals(Object object) {
		if(this == object)
			return true;
		if(object != null && object.getClass() == Test.class) {
			Test test = (Test)object;
			if(this.getId().equals(test.getId())) {
				return true;
			}
		}
		return false;
	}
}

equals要求两个对象是同一个类的实例,所以用object.getClass()==Test.class代替instanceof,这里用到了反射基础。
3. getClass()方法
返回该对象的运行时类。
4. 控制线程的暂停和运行的方法
wait()、notify()、notifyAll()
5. protected修饰的clone()方法
自定义类实现克隆如下:

//自定义类实现Cloneable接口
public class User implements Cloneable{
	//自定义实现clone()方法
	public User cloneUser() throws CloneNotSupportedException {
		//返回对象的副本
		return (User)super.clone();
	}
}

使用克隆数组比copy方法快。

Objects工具类

提供空指针安全的方法来操作对象。

String、StringBuffer和StringBuilder类

  1. String类是不可变类,所以会额外产生很多临时变量
    • int length()方法返回字符串长度
    • charAt(int index)方法返回指定位置的字符
    • int compareTo(String str)方法比较两个字符串的大小,返回长度差或第一个不相同字符的差
    • boolean contentEquals()方法比较两个字符串是否相同
    • byte[] getBytes()方法将字符串转换成数组
    • 。。。
  2. StringBuffer类和StringBuilder类相似,其对象字符串序列可变,前者线程安全,后者性能略高
    • append(String string)方法追加字符串
    • insert(int index, String string)方法插入字符串
    • reverse()方法反转字符串
    • setCharAt()方法
    • setlength()方法设置长度
    • replace(left, right, string)替换字符串
    • toString()方法将StringBuffer对象转换为String对象
  3. 几个面试题
    • 请问String s = new String("hello");创建了几个对象。
      两个。一个"hello"字符串对象,在方法区的常量池;一个s对象,在栈内存。
    • 请写出下面的结果
    		String s1 = new String("abc");
    		String s2 = new String("abc");
    		String s3 = "abc";
    		String s4 = "abc";
    
    		syso(s1==s2);  //false
    		syso(s1==s3);  //false
    		syso(s3==s4);  //true
    
    • 字符串对象一旦被创建就不能被改变。
      指的是字符串常量值不改变。
  4. 正则表达式



Math类

其构造器为private修饰,提供大量类变量(如PI、E)和类方法。
- pow()方法计算乘方
- random()方法返回一个伪随机数(0.0-1.0)

Random类和ThreadLocalRandom类

  1. Random类生成的是一种伪随机数,相同的种子相同的方法会产生相同的随机数,因此使用当前时间作种子
    Random rand = new Random(System.currentTimemillis());
  2. 使用ThreadLocalRandom在并发环境下具有更好的线程安全性,它通过current()方法生成对象
    ThreadLocalRandom rand = ThreadLocalRandom.current();
    - 生成指定范围的随机数
    int tmp = rand.nextInt(5, 10);

BigDecimal类

Java的float和double类型会引起精度丢失,BigDecimal类提供大量构造器创建对象。
- 优先推荐使用参数为String的构造器。
- 如果必须使用浮点数为参数的构造器,需要使用valueOf(double val)静态方法转换为BigDecimal对象
BigDecimal f = BigDecimal.valueOf(12.45);
- 基本运算有add()方法、subtract()方法、multiply()方法、divide()方法、pow()方法等

Calendar类

  1. 抽象类,调用getInstance()静态方法获取对象。
    Calendar cal = Calendar.getInstance();
    • 获取日期cal.getTime()
    • 修改日历指定字段的值cal.set(2013, 12, 20, 06, 30, 42)
    • add()
    • roll()
  2. java8新增了java.time包,含如下类:
    • Clock类可取代System类的currentTimemillis()
    • LocalDate类不带时区的日期,提供静态now()方法获取当前时刻
    • LocalTime类不带时区的时间
    • DayOfWeek枚举类定义了周六到周日
    • Month枚举类定义了十二个月

单例类

不允许自由创建该类的实例,只允许该类创建一个实例。

public class Singleton {
	
	//需要被static方法访问的缓存变量
	private static Singleton singleton = null;
	
	//隐藏构造器
	private Singleton() {
	}
	
	//暴露的方法,因为调用该方法之前还没有对象,所以要用static修饰
	public static Singleton getSingleton() {
		if(singleton == null)
			singleton = new Singleton();
		return singleton;
	}
}

final

  1. final修饰的变量不可被改变,但是final修饰的引用变量所引用的对象的内容可以被改变。final修饰的成员变量必须显式的指定初始值(否则没意义,默认初始化)。
  2. final定义并指定初始值的变量在编译阶段就确定下来,保存在常量池中,程序执行时直接进行宏替换。
  3. final修饰的方法不能被重写,比如Object类中的getClass()方法,
  4. final修饰的类不能被继承。

不可变类

  1. Java提供的八个包装类和java.lang.String类是不可变类,它们的实例变量不可改变。
  2. 自定义不可变类需要满足的规则:
    • 使用private和final修饰成员变量
    • 使用带参数的构造器来初始化成员变量
    • 提供getter方法,不能提供setter方法
    • 有必要的话重写Object类的hashCode()和equals方法
    • 保证成员变量引用的对象不可变
  3. 如果某个不可变实例经常被使用,需考虑对不可变实例进行缓存,减少系统开销。

System类和Runtime类

系统提供System类和Runtime类与程序的运行平台进行交互。

  • System类代表当前Java程序的运行平台,它提供了一些代表标准输入、标准输出、错误输出的类变量和用于访问环境变量、系统属性的类方法。
    比如用long Tnow = System.currentTimeMillis()返回系统当前时间。
  • Runtime类代表Java程序的运行时环境,可以访问JVM的相关信息。

内部类

Java8新增的lambda表达式

参见Lambda入门

枚举类

枚举类是一种特殊的类,使用enum关键字, 定义如下:

public enum SeasonEnum {
	SPRING, SUMMER, FALL, WINTER;
}

使用如下:


public class EnumTest {
	public void getEnum() {
		
		//枚举类默认的values()方法返回所有实例
		for(SeasonEnum s : SeasonEnum.values()) {
			System.out.println(s);
		}
	}
	public void select(SeasonEnum s) {
		//swich的控制表达式可以是枚举类型
		switch (s) {
			//无需添加枚举类限定
			case SPRING:
				System.out.println("spring");
				break;
			case SUMMER:
				System.out.println("summer");
				break;
			case FALL:
				System.out.println("fall");
				break;
			case WINTER:
				System.out.println("winter");
				break;
		
		}
	}
}
原文地址:https://www.cnblogs.com/pycrab/p/8735154.html