java基础类,方法和对象

api 即为应用程序编程接口,英文为Application programming interface

System

System.currentimeMillis 获取毫秒数(事件戳)

System.exit 退出虚拟机

System.gc 建议运行gc

Object类

Object 根类,所有类的超类

toString 方法,默认打印类路径+对象地址哈希

clone 负责对象克隆

equals 判断两个对象是否相等,默认比较引用地址

hashCode 获取对象哈希值.底层C++实现。返回内存地址的哈希值。

finalize 垃圾回收器调用的方法,默认啥也不干。protected方法,由jvm自动调用。当一个对象即将被垃圾回收器回收的时候,触发

jvm GC 垃圾太少,时间不到Jvm就不会回收

建议GC启动,System.gc(),启动概率会高

处理输入

Scanner类,从指定位置读取输入,并按指定分隔符分割。常见用法是创建一个从标准输入读取的扫描器,控制台中读取。

Scanner sc = new Scanner(System.in);
int i = sc.nextInt();

使用其他类的步骤一般为导包,创建,使用,如

import java.util.Scanner
    
Scanner sc = new Scanner(System.in);

但是你肯定也见到了System这些不需要导入的类,原因在于这些类位于java.lang包下,而 java.lang包下的内容默认被导入

匿名对象

anoymous 匿名对象

对一些只使用一次而没有指定名称对象的称呼,例如

new Person("Java", 25).name;

随机数

使用java.util.Random创建将随机数

例如

Random r = new Random(); // 创建随机数种子
r.nextInt(); //获取随机数
r.nextInt(3); // 指定范围内随机数 0~3,不包含3(从0开始)

ArrayList

集合ArrayList和数组的区别是,ArrayList集合的长度是可以变化的。

<E>代表泛型,指存储的类型,泛型只能够存储引用类型

所以如果需要保存基本类型的话,需要一个包装类。例如int数据类型的包装类Integer

同时在日常使用中,基本类型的包装类和基本类型之间进行运算时并不需要多余操作,因为java会自动完成装箱,拆箱 基本类型和其对应的包装类之间的转换

同时对于ArrayList直接打印,打印的将不是地址而是内容,这是因为java对ArrayList的toString方法进行了处理。

ArrayList类型的常用成员方法有:

  1. add方法,相当于js的Array中的push

  2. get 获取指定索引的值

  3. remove 删除索引位置的值

  4. size 获取集合的尺寸

字符串类

String 字符串类,所有字符串字面量都是字符串类的实例

比较String 不能够使用 == 。应该使用equals方法,因为他并不是基本数据类型

String 重写了toString方法,不然应该是java.lang.String@xxxxx

字符串不可改变,虽然它表现的像是char[]但是底层实现确是byte[]

public String String(); // 创建 空白字符串
public String String(char[] array); // 从字符数组创建
public String String(byte[] array); // 从字节数组创建

在堆当中存在有一个字符串常量池,对于两个相同的字符串字面量,(jvm在加载时进行的优化)当他们被赋值给一个变量,java返回的是在字符串常量池中的同一份引用。例如:

jshell> var s1 = "123";
s1 ==> "123"

jshell> var s2 = "123";
s2 ==> "123"

jshell> s1 == s2
$3 ==> true

jshell> var s3 = s1;
s3 ==> "123"

jshell> var s4 = s2;
s4 ==> "123"

jshell> s3 == s4
$6 ==> true

jshell>

字符串常量池 在方法区中。字符串在java中使用频繁,所以使用了字符串常量池。

new String("A")将会在字符串常量池转创建常量"A",并在堆中创建字符串对象保存常量池中"A"的地址。

同时每次通过new操作符都会创建一个新的对象,而直接使用字面量时,只会返回常量池中的引用,所以会有如下代码。

String a = "1";
String b = "1";
System.out.println(a == b); // 将会打印true

String c = new String("1");
String d = new String("1");
System.out.println(c == d); // 将会打印false

System.out.println(a == c); // 将会打印false

构造方法

public String String(bytes[] byteArr)

public String String(bytes[] byteArr, int begin, int length) 将数组中的一部分转换成为字符串

public String String(char[] charArr)

public String String(char[] charArr, int begin, int length)

常用方法

public boolean equals(Object obj) 可进行字符串的内容比较,equals具有对称性,也即是说不论是A在前还是B在前都是一样的。但总是推荐常量写在前面,因为对于一个不确定的变量他可能回事null

String str1 = null;
"1".equals(str2);
str1.equals("1"); // 将会抛出异常

equalsIgnoreCase 忽略大小写相等性比较

concat 拼接字符串

charAt 获取指定索引字符

indexOf 指定字符首次出现的位置

substring 截取子字符串,但拥有1个参数时,截取从指定位置开始到字符串结尾的字符,2参数,begin到end,但不包括end位置的字符

toCharArray 返回字符数组

getBytes 返回bytes数组

replace 替换指定字符串

split 按照指定间隔符分割字符串,提供的参数需要是正则表达式

contains 是否包含指定字符串

endWith 判断字符串是否以指定字符串结尾

startWith 判断字符串是否以指定字符串开始

isEmpty 判断字符串是否为空

lastIndexOf 判断指定字符串在字符串中最后一次出现的索引

toLowerCase 将字符串转换为小写

toUpperCase 将字符串转换为大写

trim 剪切首尾空白

valueOf 静态方法.将其他类型转换为字符串

常用属性

length 字符串的长度

StringBuffer / StringBuilder

StringBuffer和StringBuilder存在的原因是因为Sting类型中存储字符串实际是一个字节数组。

@Stable
private final byte[] value;

而这个字节数组是被final修饰的,也就是说value属性是不可更改的。这意味着在对一个字符串进行修改操作的时候,又会创建一个新的String对象。

在遇到频繁的字符串拼接等操作的情形时,明显会有比较大的性能耗费。

而StringBuffer/StringBuilder的value成员不为final修饰,在使用append进行字符串拼接操作时直接修改value属性中的byte数组,减少了性能损耗。

同时StringBuffer的byte数组初始化容量为16,所以为了减少在超出byte容量以后数组空间的重新申请,可以在初始化时提供一个较大的(合适的)初始化数组大小。

StringBuffer和StringBuilder的区别是前者是线程安全的,而后者不是线程安全的。

Arrays静态类

java.util.Arrays 提供数组静态方法

toString 将参数数组转换称为字符串

sort 按照默认升序对数组进行排序

Math静态类

java.util.Math 数学相关的类,提供数学相关的静态方法

abs 返回参数的绝对值

ceil 将参数向上取整

floor 将参数向下取整

round 四舍五入

包装类

八种基本类型对应的包装类型

Byte,Short,Interger,Long,Float,Double,Boolean,Character

Short,Interger,Long,Float,Double继承自Number,同时都有常量属性,最大值,最小值。

Number具有类似于intValue,shortValue拆箱的方法

装箱,拆箱。 但是需要注意==不会触发自动拆箱机制

Integer a = 500;
Integer b = 500;
a == b; // false

Integer c = 1;
Integer d = 1;
c == d; // true

但是为什么这里的c == d为true,因为常量池的存在。我们可以看一下Integer的valueOf方法

@HotSpotIntrinsicCandidate
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

IntegerCache实际上是一个内部静态类。可以看到如果没有超过内部静态类中定义的heigh和low的话,直接就是返回的IntegerCache里面的数字包装类对象。而实际上low为-128,heigh为127.也就是共256个数字

这个cache存在的意义是,不用为每一个数字类型的包装类创建一个单独的对象,即使他们包装的内容是相同的,减少了内存的占用(虽然我觉得这并不是一件特别有意义的事情)。

Integer

parseInt 静态方法 字符串转换成为int 使用字符串的话触 发NumberFormatException

toBinaryString 静态 转换成为二进制字符串

toHexString 静态 转换称为16进制字符串

valueOf 把给定参数转换成为本类型

Date时间日期类

java.util.Date

new Date() 默认返回当前时间日期

new Date(事件戳) 根据事件戳创建日期对象

java.text.SimpleDateFormat 日期格式化

yyyy MM dd HH mm ss SSS 分别代表年 月日 小时 分钟 秒 毫秒

new SimpleDateFormat(String formatString) 需要提供一个字符串形式的格式化参数,

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm");
String nowString = dateFormat.format(new Date());
System.out.println(nowString); // 2020/06/13 13:52

SimpleDateFormat的 parse方法 可以 将String转换称为Date类型,但字符串格式需要和SimpleDateFormat指定的日期格式相同

数字格式化

DecimalFormat 数字格式化器需要提供一个格式化字符串

BigDecimal

BigDecimal类型 适合财务软件,适合10进制的数。同时该类型需要使用指定方法进行计算。并且对于无法转换精确的用十进制表示的计算结果还会抛出错误。

enum枚举类型

枚举类型 引用数据类型

enum ,一般的使用方法是对情况进行分类

enum Result {
    // ...
}

switch支持string,int,char,short,byte。。。以及枚举

异常 Excaption

异常类,异常对象

异常时jvm运行过程中发现的非正常情况的一个描述。

一般我们都需要对异常进行捕获和处理。否则一直向上抛,将抛给jvm,程序也就将退出。

捕获异常有两种方式:

  1. throws抛给上一级(函数体内throw,或函数定义中)
  2. try。。catch

前一种是捕获但不处理,继续往上抛,另一种是立即处理。

同时异常分为两类:

  1. Exception的直接子类(编译时异常/受控[检]异常)
  2. RuntimeException 运行时异常 (非受控/受检异常)

前者和后者的区别是,前者希望你立即捕获。但不管你捕获之后怎么处理。因为他认为这是一个一定会发生的情况。

而后者并不要求你立即处理,你可以在任何时候和地点处理,甚至你可以不处理(但程序将会终止)。他认为这是一个可能发生的情况。

使用catch语句有一种新写法,如:

catch(FileNotFoundException | ArithmeticException e) {
    // ... JDK8的新特性,可以这样写。
}

异常和错误不同。错误发生,错误是不能处理的,java程序只有一个结果退出。

异常对象 方法

每个异常对象都有两个重要的方法:

  1. getMessage
  2. printStackTrace 异步线程方式打印

stackTrace从上往下看(不用看类库的报错),因为打印的是当前运行栈的信息。

自定义异常

继承自Exception 编译时异常 要求立即捕获并处理 // 语法

继承自RuntimeException 运行时异常 不要求立即捕获并处理 // 运行

重写之后的方法不能比重写之前的方法抛出更多更宽泛的(编译时异常)异常!!!

finally 语句

finally语句必须和try一起出现,不能够单独编写,它最后执行,并且一定会执行(无论是否正常执行)。可以用来做对资源的释放处理。

例如:

try {
    System.out.println("try..");
    return ;
} finally {
    System.out.println("finally..."); // ...这里的finally语句依然会被执行
}

除非调用System.exit()finally语句将不会执行。

public static int m() {
    int i = 100;
    try {
        return i;
    } finally {
        i ++;
    }
}
// .... 

System.out.println(m()); // why? 100
private static int[] m() {
    int[] i = new int[2];
    try {
        throw new Exception();
    } catch (Exception e) {
        return i;
    } finally {
        i[0] = 1;
    }
}
// ...
System.out.println(Arrays.toString(m())); // [1, 0]

可以看到为什么第一个代码段会输出100, 而第二个代码段会输出[1, 0]。这是因为:实际上对于finally中使用的try..catch中的变量,finally使用了中间变量来承载。而i作为一个基础类型,所以并没有变化。

final 和 finally 区别

final和finally语义相同,但是final用来修饰成员和class,表示不能被覆盖和继承。但是finally表示try无论成功或失败都要执行的语句

Iterable 迭代接口

实现了Map接口的几乎都没有 没有实现迭代接口

如果通过外部改变集合结构,迭代器必须重新获取。迭代器实际上是保存了源集合的一个快照,如果迭代过程中源状态与快照状态不同,就会报错。而通过外部改变并没有通知迭代器更新快照。

实现了迭代器接口的类需要实现下面三个方法:

  1. iterator 返回一个迭代器对象 (必须实现的)
  2. forEach 对每个元素进行操作
  3. spliterator

实现了迭代接口的类,必须实现一个iterator方法,该方法返回一个iterrator(迭代器对象),该迭代器对象上主要拥有下面三个方法:

  1. hasNext 是否有下一个元素

  2. next 返回下一个元素

  3. remove 删除迭代器指向的当前元素

迭代器最初并非指向第一个元素

Map 接口

以键值对方式存储数据和Collection没有继承关系。

key,value都是引用。Key主导。

常用方法

clear 清理所有元素

containsKey 是否包含指定key

containsValue 是否包含指定Value

isEmpty 是否为空

get 通key获取value

remove 通key删除节点

ketSet 获取所有key组成的集合

put 添加键值对

size 获取元素个数

values 获取所有value

entrySet 将Map集合转换称为Set集合,类型为Map.Entry<K, V> 此种遍历效率更高,适合大数据量

实现该接口的常用类有

  1. HashMap 存储结构 哈希表(又称散链表) 线程不安全

  2. Hashtable 存储结构 哈希表 但是线程安全(因为效率低,用的少,有其他实现)

    ​ 直接子类之一:Properties 线程安全,继承自Hashtable。Key/Value只支持String类型 存setProperty 取setProperty

  3. TreeMap 实现了SortedMap(接口继承自Map接口,存储在TreeMap的Key) 存储结构为红黑树

HashMap

map.put(k, v)

底部代码将会把k, v封装node对象

并同时调用Key的hashcode方法得出hash值并通过一定算法得到一个值作为数组下标(有可能不同hash得到相同的值,但对使用并无影响),如果数组下标位置为空,就填充到该位置。如果数组下标位置不为空,就尝试添加到该位置所在链表。

首先依次对比(equals)该位置所在链表元素的key,如果没有相同的key元素就添加到链表的结尾。否则就替换遇到的首个key相同的元素的值。

map.get(k)

通过hashCode方法算出Key的哈希,通过算法得到哈希对应的数组下标。如果在数组对应位置有单向链表(没有直接返回null),则在链表中搜索是否有和k相同的的元素,如果有返回该元素的value,否则搜索到末尾返回null。

放在HashSet集合中的元素实际上就是放到HashMap的key部分中了,所以HashSet中的元素需要同时重写hashCode和equals方法。

为了散列分布均匀,需要在重写Node对象hashCode方法时有一定的技巧

HashMap默认容量16(如果提供初始化容量的话,尽量提供2的倍数),当满足容量的0.75(3/4)时数组开始扩容,扩容之后的容量将为原容量的2倍。

Hashtable

虽然HashMap的Key/Vlue允许为null,但HashTable的Key/Value不允许null

存储结构同样是哈希表,但和HashMap相比,它的存取时线程安全的。

Hashtable的初始化容量为11,扩容时更改容量为为原容量*2+1

集合 Collection (接口)

实现了Iterable接口。

集合其实就是一个容器,用来容纳其他类型的数据。

集合中不能存储基本数据类型。它其实存储的是一个指针。

不同的集合底层的对应不同的数据结构,往不同的集合中放数据,就是将数据放到了不同的数据结构中。

所有的集合类/以及相关的接口都在java.util包中

集合(Collection)可以分为有序的List和无序的Set

常用方法

add 添加元素

clear 清楚所有元素

contains 是否包含指定元素,通过equals方法比较

size 获取集合元素个数

remove 删除集合中的某个元素,通过equals比较

isEmpty 判断集合是否为空

toArray 将集合转换为数组

List 接口

实现该接口类的特点:元素单个存储,他的元素存储总是可重复并且有序的。

实现该接口的常用类(非抽象类)有:

  1. ArrayList 存储结构为数组,初始化容量默认为10(在第一次add方法时初始化)(可以指定容量[建议初始化容量,减少数组扩容。]) 访问时非线程安全的
    1. 无参构造
    2. 提供初始化容量大小
    3. 提供其他的实现了集合Collection接口的参数来创建ArrayList
  2. LinkekList 存储结构为双向链表
  3. Vector 存储结构为数组,初始化容量为10 为线程安全的但是效率低,一般采用其他方法实现线程安全的

常用方法

add 默认向末尾添加,有个重载,在指定位置添加元素

remove 删除指定位置元素

get 获取指定位置元素

set 修改指定位置元素

indexOf 获取指定元素出现的首个位置索引

lastIndexOf 获取指定元素出现的最后一个位置索引

Set 接口

存储特点,无序不可重复 。也就是模拟数学中的集合。

实际上所有实现Set接口的类都是通过实现了Map接口的类来定义的。

实现类有:

  1. HashSet 实际存储结构为HashMap(哈希表结构)来提供支持,它的值将被存储到HashMap节点的Key中
  2. TreeSet 同时实现了SortedSet(可排序集合接口继承自Set接口)接口 底层存储结构TreeMap,它的值将被存储到TreeMap的Key中

TreeSet

指定比较规则

Collections 集合工具类

Collections.synchronizedList 将非线程安全的集合转换称为线程安全的集合。

Collections.sort 将集合进行排序(集合元素需要实现Comparable接口)

泛型

泛型属于在编译期的作用

用泛型来指定集合中的数据类型,这样用了泛型,集合中的数据类型更加统一。

自动类型推断

JDK8之后

List<Animal> list = new ArrayList<>();

foreach

for (int i : arr) {
    // ...
}
原文地址:https://www.cnblogs.com/freesfu/p/13735426.html