java笔记
发表于:2024-02-04 | 分类: java学习笔记

Java学习笔记

一、数组

1、遍历数组

  • 法1
1
2
3
4
5
6
7
8
9
10
11
public class Deo{
public static void main(String[] args){
int b[][]={{1}.{2,3},{4,5,6}};//定义二维数组
for(int k=0;k<b.length;k++){
for(int c=0;c<b[k].length;c++){
System.out.print(b[k][c]);
}
System.out.println();
}
}
}
  • 法2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class deo {
public static void main(String[] args) {
int arr[][]= {{4,3},{2,1}};
System.out.println("数组中的元素是:");
int i=0;//外层循环计数器变量
for(int x[]:arr) { //外层循环变量为一维数组
i++;
int j=0;
for(int e:x) {
j++;
if(i==arr.length&&j==x.length) {
System.out.print(e);
}else {
System.out.print(e+"、");
}
}
}
}

}

2、填充替换数组元素

  • fill(int [] arr,int value);
  • 1.arr:要进行填充的数组;
  • 2.value:要存储数组中所有元素的值
1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.Arrays; //导包
public class swap {
public static void main(String[] args) {
int arr[]=new int[5];
Arrays.fill(arr, 8);//使用同一个值对数组进行填充
for(int i=0;i<arr.length;i++) {
System.out.println("第"+(i+1)+"个元素的值是:"+arr[i]);
}

}

}

  • fill(int[] arr,int from,int to,int value);
  • 1.arr:要进行填充的数组;
  • 2.from:要使用指定值填充的第一个元素的索引(包括);
  • 3.to:要使用指定值填充的最后一个元素的索引(不包括);
  • 4.value:要分配给数组指定范围中的每个元素的值.
1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.Arrays;
public class swap {
public static void main(String[] args) {
int arr[]={5,4,2,1,2};
Arrays.fill(arr,1,3, 8);//使用同一个值对数组进行填充
for(int i=0;i<arr.length;i++) {
System.out.println("第"+(i+1)+"个元素的值是:"+arr[i]);
}

}

}

3、对数组进行排序

Arrays.sort(object);

object为需要进行排序的数组名称.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.Arrays;
public class swap {
public static void main(String[] args) {
int arr[]={5,4,2,1,2};
Arrays.fill(arr,1,3, 8);//使用同一个值对数组进行填充
Arrays.sort(arr);//从小到大排序
for(int i=0;i<arr.length;i++) {
System.out.println("第"+(i+1)+"个元素的值是:"+arr[i]);
}

}

}

冒泡排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class BubbleSort {
public static void main(String[] args) {
int []arr=new int[] {12,23,43,54,65};//创建一个数组
BubbleSort sorter=new BubbleSort();//创建冒泡排序类的对象
sorter.sort(arr);//调用排序方法,对数组进行排序
}
public void sort(int []arr) {//冒泡排序
for(int i=1;i<arr.length;i++) {//排序趟数
for(int j=0;j<arr.length-i;j++) {
if(arr[j]>arr[j+1]) {
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
for(int i:arr) {//打印输出数组
System.out.print(">"+i);
}
System.out.println();
}
}

直接选择排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class SelectSort {//选择排序
public static void main(String[] args) {
int[]arr= {43,32,4,5,67,7};
sort(arr);
}
public static void sort(int arr[]) {
//每次排序一趟找出待排序元素中的最大值放到末尾
int index;
for(int i=1;i<arr.length;i++) {
index=0;
for(int j=1;j<=arr.length-i;j++) {
if(arr[j]>arr[index]) {
index=j;
}
}
//交换index和arr.length-i的值
int temp=arr[arr.length-i];
arr[arr.length-i]=arr[index];
arr[index]=temp;
}
for(int i:arr) {//打印输出数组
System.out.print(">"+i);
}
System.out.println();
}

}

反转排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class ReverseSort {
public static void main(String[] args) {
int arr[]= {11,22,33,44,55,66,77};
sort(arr);
}
public static void sort(int []arr) {
System.out.println("原数组元素内容为:");
for(int i:arr) {
System.out.print(">"+i);
}
System.out.println();
int temp,len=arr.length;
for(int i=0;i<len/2;i++) {
//交换元素位置
temp=arr[i];
arr[i]=arr[len-i-1];
arr[len-1-i]=temp;
}
System.out.println("新数组元素内容为:");
for(int i:arr) {
System.out.print(">"+i);
}
System.out.println();

}

4、复制数组

copyOf(arr,int newlength);

arr:要进行复制的数组;

newlength:int型常量,指复制后的新数组的长度。如果新数组长度大于原数组长度,则用0(null)来填充;

若小于原数组长度,则会从原数组的第一个元素开始截取至满足新数组长度为止。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.Arrays;
public class swap {
public static void main(String[] args) {
int arr[]={5,4,2,1,2};
int arr2[]=Arrays.copyOf(arr,3);//复制数组,新数组长度小于原数组
int arr3[]=Arrays.copyOf(arr, 10);//复制数组,新数组长度大于原数组,多的部分用0填充
for(int i=0;i<arr.length;i++) {
System.out.println("第"+(i+1)+"个元素的值是:"+arr[i]);
}
System.out.println("----------------");
for(int i=0;i<arr2.length;i++) {
System.out.println("第"+(i+1)+"个元素的值是:"+arr2[i]);
}
System.out.println("----------------");
for(int i=0;i<arr3.length;i++) {
System.out.println("第"+(i+1)+"个元素的值是:"+arr3[i]);
}
System.out.println("----------------");
}

}

copyOfRange(arr,int from,int to);

arr:要复制的数组

from:指开始复制数组的索引位置(包括);

to:指开始复制数组的结束索引位置(不包括);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class swap {
public static void main(String[] args) {
int arr[]={5,4,2,1,2};
int arr2[]=Arrays.copyOfRange(arr,0,3);//复制数组
int arr3[]=Arrays.copyOfRange(arr,0,10);//超过部分会用0填充
for(int i=0;i<arr.length;i++) {
System.out.println("第"+(i+1)+"个元素的值是:"+arr[i]);
}
System.out.println("----------------");
for(int i=0;i<arr2.length;i++) {
System.out.println("第"+(i+1)+"个元素的值是:"+arr2[i]);
}
System.out.println("----------------");
for(int i=0;i<arr3.length;i++) {
System.out.println("第"+(i+1)+"个元素的值是:"+arr3[i]);
}
System.out.println("----------------");
}

}

5、查询数组

binarySearch(Object[] arr, Object value); //返回的是搜素值得索引,否则返回-1或‘ - ’(插入点);

arr:要搜素的数组;

value:要搜素的值.

1
2
3
4
5
6
7
8
9
10
11
12
import java.util.Arrays;
public class swap {
public static void main(String[] args) {
int arr[]={5,4,2,1,3};
int index=Arrays.binarySearch(arr, 3);
System.out.println("3的索引位置是:"+index);
int index2=Arrays.binarySearch(arr, 11);
System.out.println("11的索引位置是:"+index2+"(数组中未找到该元素)");
}

}

binarySearch(object[] arr,int from,int to,int value);

arr:要进行检索的数组;

from:指定范围检索的开始处索引(包括);

to:指定范围检索的结束处索引(不包括);

value:要搜素的值.

1
2
3
4
5
6
7
8
9
10
11
import java.util.Arrays;
public class swap {
public static void main(String[] args) {
int arr[]={5,4,2,1,3};
int index=Arrays.binarySearch(arr,0,5, 3);
System.out.println("3的索引位置是:"+index);
int index2=Arrays.binarySearch(arr,0,5, 11);
System.out.println("11的索引位置是:"+index2+"(数组中未找到该元素)");
}

}

二、字符串

单个字符可以用char类型保存,多个字符组成的文本就需要保存在String对象中。String通常称为字符串,一个String对象最多可以保存2^32-1个字节(占用4GB空间大小)的文本内容。

1、声明、创建字符串

1
2
3
4
5
6
7
8
9
10
11
12
String str;//声明字符串
//声明的字符串变量必须经过初始化后才能使用,否则编译器会报出"变量未被初始化错误"。
//创建字符串
char a[]={'g','o','o','d'};
String s=new String(a); //等价于String s=new String("good");

char a[]=['s','t','u','d','e','n','t'];
String s=new String(a,2,4);//等价于String s=new String("udent");


String str1;
str1="Student";

2、连接字符串

1
2
3
4
5
6
7
8
9
10
11
12
public class Link {
public static void main(String[] args) {
String str1=new String("春色绿千里");
String str2=new String("马蹄香万家");
String s=str1+"\n"+str2;
System.out.println(s);
int booktime=4;
float practice=6.5f;
System.out.println("我每天花费"+booktime+"小时看书;"+practice+"小时上机训练");
}
}

3、获取字符串信息

  • 使用String类的length()方法可以获取声明的字符串对象的长度.
  • indexOf(String s);//该方法返回参数字符串s在指定字符串中首次出现的索引位置。若未找到字符串s,则会返回-1.
  • lastIndexOf(String str);//该方法返回参数字符串s在指定字符串中最后一次出现的索引位置。若未找到字符串s,则会返回-1.
  • charAt(int index)方法可以将指定索引处的字符返回。
1
2
3
4
5
6
7
8
9
10
11
12
//1.获取字符串长度
String str="We are student";
int size=str.length();

//2.字符串查找
String str="We are student";
int index=str.indexOf("a");
int index2=str.lastIndexOf("a");

//3.获取指定索引位置的字符
String str="hello world";
char mychar=str.chatAt(2);

4、字符串操作

  • 获取子字符串

substring(int begin);

该方法返回的是从指定的索引位置开始截取到该字符串结尾的子串

substring(int begin,int end);

该方法返回的是从字符串某一索引位置开始截取到某一索引位置结束的子串。

1
2
3
4
5
//1.获取子字符串
String sub1=str.substring(2);
String sub2=str.substring(1,2);
System.out.println(sub1);
System.out.println(sub2);
  • 去除空格

trim();

该方法返回字符串的副本,忽略掉前导空格和后导空格。

1
2
3
4
//2.去除空格
String s=" Java 学习 ";
System.out.println(s.length());
System.out.println(s.trim().length());
  • 字符串替换

replace(target, replacement);

该方法可以实现将指定的字符或字符串替换成新的字符或字符串。

target:要替换的字符或字符串

replacement:用于替换原来字符串的内容

1
2
3
4
//3.替换字符串
String s1="helloworld";
String s2=s1.replace( "l","L");
System.out.println(s2);
  • 判断字符串的开始与结尾

startWith(String prefix);

该方法判断当前字符串对象的前缀是否为参数指定的字符串。

prefix是指作为前缀的字符串。

endWith(String suffix);

该方法用于判断当前字符串是否以给定的字符串结束。

suffix是指作为后缀的字符串。

1
2
3
4
5
6
7
//4.判断字符串的开始与结束
String num1="22045612";
String num2="21304578";
boolean flag1=num1.startsWith("22");
boolean flag2=num2.endsWith("11");
System.out.println("字符串num1是以'22'开始的吗?"+flag1);
System.out.println("字符串num2是以'11'结束的吗?"+flag2);
  • 判断字符是否相等

equals(String str);

该方法用于判断两个字符串是否相等,且区分大小写,返回的是boolean类型。

equalsLgnoreCase(String str);

该方法用于判断两个字符串是否相等,忽略字母的大小写,返回的是boolean类型。

1
2
3
4
5
6
7
8
//5.判断字符串是否相等
String sh1="helloworld";
String sh2="HElloworld";
boolean a1=sh1.equals(sh2);//区分大小写
boolean a2=sh1.equalsIgnoreCase(sh2);//忽略大小写
System.out.println(a1);
System.out.println(a2);

  • 按字典序比较两个字符串

compareTo(String str);

该方法按照字典顺序比较两个字符串,若按照字典顺序此String对象位于参数字符串之前则返回一个负整数,位于之后,则返回一个正整数,如果两个字符串相同则返回0.

1
2
3
4
5
//6.按字典顺序比较两个字符串
String sa1="hello";
String sa2="hallo";
int compare=sa1.compareTo(sa2);
System.out.println(compare);
  • 字母大小写转换

toLowerCase();

将字符串中所有大写字母转化为小写字母;

toUpperCase();

将字符串中所有小写字母转化为大写字母

1
2
3
4
5
6
//7.字母大小写转换
sa1="heelll";
String ss=sa1.toUpperCase();
String sss=ss.toLowerCase();
System.out.println(ss);
System.out.println(sss);
  • 字符串分割

1.split(String sign);

该方法可以将给定的分割符对字符串进行拆分,其中sign为分割字符串的分割符。

2.split(String sign,int limit);

该方法可以根据给定的分割符对字符串进行拆分,并限定拆分的次数,其中sign为分割字符串的分割符,limit为限制的拆分次数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//8.字符串分割
str="192.168.0.1";
String[]firstArray=str.split("\\.");
String[]secondArray=str.split("\\.",2);
System.out.println("str的原值为:["+str+"]");
System.out.print("全部分割后的结果为:");
for(String a:firstArray) {
System.out.print("["+a+"]");
}
System.out.println();
System.out.print("分割两次后的结果为:");
for(String a:secondArray) {
System.out.print("["+a+"]");
}
System.out.println();

5、字符串生成器

如果对字符串进行拼接操作,每次拼接,都会构建一个新的String对象,既耗时,又浪费内存空间,而这种操作还不可避免。因此我们可以通过StringBuild类来解决这个问题。

StringBuilder是一个可变的字符串类,我们可以把它看作一个容器,这里的可变指的是StringBuilder对象中的内容是可变的

StringBuilder和String的区别:

  • StringBuilder:内容是可变的
  • String:内容是不变的

构造方法

public StringBuilder(); 创建一个空白可变字符串对象,不含任何内容

public StringBuilder(String str); 根据字符串的内容,来创建可变字符串对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//构造方法
public class Builder {
public static void main(String[] args) {
//public StringBuilder();创建一个空白可变字符串对象,不含任何内容
//public StringBuilder(String str);根据字符串的内容,来创建可变字符串对象
StringBuilder sb=new StringBuilder();
System.out.println("sb:"+sb);
System.out.println("sb.length():"+sb.length());
StringBuilder sb2=new StringBuilder("hello");
System.out.println("sb2:"+sb2);
System.out.println("sb2.length():"+sb2.length());
}
}

添加和反转方法

public StringBuilder append(任意类型) ; 添加数据,并返回对象本身

public StringBuilder reverse(); 返回相反的字符序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//添加和反转方法
public class Builder {
public static void main(String[] args) {
//public StringBuilder append(任意类型);添加数据,并返回对象本身
//public StringBuilder reverse();返回相反的字符序列
StringBuilder sb=new StringBuilder();
StringBuilder sb2=sb.append("hello");
System.out.println("sb2:"+sb2);
System.out.println("sb2.length():"+sb2.length());
sb.append("java");
//链式编程
sb.append(" good ").append("C++ ");
System.out.println("sb:"+sb);
System.out.println("sb.length():"+sb.length());
sb.reverse();
System.out.println("sb:"+sb);
System.out.println("sb.length():"+sb.length());
}
}

StringBuilder和String的相互转换

  • StringBuilder转换为String

    public String toString(); 通过toSTring可以实现把StringBuilder转换为String

  • String转换为StringBuilder

    public StringBuilder(String str); 通过构造方法实现把String转换为StringBuilder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package StringTest;
public class zhuanhuan {
public static void main(String[] args){
//public String toString();通过toSTring可以实现把StringBuilder转换为String
//public StringBuilder(String str);通过构造方法实现把String转换为StringBuilder
StringBuilder sb=new StringBuilder();
sb.append("Hello");
String str=sb.toString();
System.out.println(str);
String temp="java";
StringBuilder temp2=new StringBuilder(temp);
System.out.println(temp2);
}
}

6、正则表达式

正则表达式可以检验字符串是否满足一定的规则,并用来校验数据格式的合法性。

作用:

  • 校验字符串是否满足规则
  • 在一段文本中查找满足要求的内容

字符类(只匹配一个字符)

表达式 说明
[abc] 只能是a,b,c
[^abc] 除了a,b,c之外的任何字符
[a-zA-Z] a到z,A到Z,包括(范围)
[a-d[m-p]] a到d或者m到p
[a-z&&[def]] a-z和def的交集,为:d,e,f
[a-z&&[^bc]] a-z和非bc的交集。等同于[ad-z]
[a-z&&[^m-p]] a到z除了m到p的交集。等同于[a-lq-z]]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package Regex;

public class RegexDemo2 {
public static void main(String[] args) {
//public static matches(String regex): 判断是否与正则表达式匹配,匹配返回true

//只能是a,b,c
System.out.println("--------1--------");
System.out.println("a".matches("[abc]")); //true
System.out.println("z".matches("[abc]")); //false
System.out.println("ab".matches("[abc]")); //false 一个中括号只表示一个字符,含有2个字符故会返回false


//不能出现a,b,c
System.out.println("--------2---------");
System.out.println("a".matches("[^abc]")); //false
System.out.println("z".matches("[^abc]")); //true
System.out.println("zz".matches("[^abc]")); //false 一个中括号只表示一个字符,含有2个字符故会返回false
System.out.println("zz".matches("[^abc][^abc]")); //true

//a到z A到Z(包括头尾的范围)
System.out.println("--------3--------");
System.out.println("a".matches("[a-zA-Z]")); //true
System.out.println("z".matches("[a-zA-Z]")); //true
System.out.println("aa".matches("[a-zA-Z]")); //false
System.out.println("zz".matches("[a-zA-Z]")); //false
System.out.println("0".matches("[a-zA-Z]")); //false

//a[d[m-p]] a到d 或m-p
System.out.println("--------4--------");
System.out.println("a".matches("[a-d[m-p]]")); //true
System.out.println("d".matches("[a-d[m-p]]")); //true
System.out.println("m".matches("[a-d[m-p]]")); //true
System.out.println("p".matches("[a-d[m-p]]")); //true
System.out.println("e".matches("[a-d[m-p]]")); //false
System.out.println("0".matches("[a-d[m-p]]")); //false

//[a-z&&[def]] a-z和def的交集,为def
//细节:如果要求两个范围的交集,那么需要写符号&&
//如果写成了&,那么此时&不表示交集,仅仅表示一个简简单单的符号&
System.out.println("--------5---------");
System.out.println("a".matches("[a-z&[def]]")); //true
System.out.println("&".matches("[a-z&[def]]")); //true
System.out.println("a".matches("[a-z&&[def]]")); //false
System.out.println("d".matches("[a-z&&[def]]")); //true

// [a-z&&[^bc]] a-z和非bc的交集。 等同于[ad-z]
System.out.println("--------6--------");
System.out.println("a".matches("[a-z&&[^bc]]")); //true
System.out.println("b".matches("[a-z&&[^bc]]")); //false
System.out.println("d".matches("[a-z&&[^bc]]")); //true
System.out.println("0".matches("[a-z&&[^bc]]")); //false

// [a-z&&[^m-p]] a到和和除了m到p的交集。 等同于[a-lq-z]
System.out.println("--------7--------");
System.out.println("a".matches("[a-z&&[^m-p]]")); //true
System.out.println("m".matches("[a-z&&[^m-p]]")); //false
System.out.println("0".matches("[a-z&&[^m-p]]")); //false


}
}

预定义字符(只匹配一个字符)

表达式 说明
. 任何字符
\d 一个数字:[0-9]
\D 非数字:[^0-9]
\s 一个空白字符[\t\n\x0B\f\r]
\S 非空白字符[^\s]
\w [a-zA-Z_0-9] 英文、数字、下划线
\W [^\w] 一个非单词字符

数量词

X? X,一次或0次

X* X,零次或多次

X+ X,一次或多次

X{n} X,至少n次

X{n,m} 至少n但不超过m次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package Regex;

public class RegexDemo3 {
public static void main(String[] args) {
// \ 转义字符 改变后面那个字符原来的含义


// .表示任意一个字符
System.out.println("你".matches("..")); //false
System.out.println("你a".matches("..")); //true

// \\d只能是任意一个数字 简单来记:两个\\表示一个\
System.out.println("a".matches("\\d")); //false
System.out.println("0".matches("\\d")); //true
System.out.println("22".matches("\\d")); //false

// \\w表示只能是一位单词字符 [a-zA-Z_0-9]
System.out.println("0".matches("\\w")); //true
System.out.println("a".matches("\\w")); //true
System.out.println("_".matches("\\w")); //true
System.out.println("W".matches("\\w")); //true
System.out.println("1w".matches("\\w")); //true


// \\W 非单词字符
System.out.println("你".matches("\\W")); //true
//以上正则表达式只能校验单个字符

//必须是数字 字母 下划线 至少6位
System.out.println("----------------");
System.out.println("22138ws32".matches("\\w{6,}")); //true
System.out.println("23_f".matches("\\w{6,}")); //false

//必须是数字和字符 必须是4位
System.out.println("23dF".matches("[a-zA-Z_0-9]{4}"));//true
System.out.println("23_F".matches("[a-zA-Z0-9]{4}"));//false
System.out.println("23df".matches("[\\w&&[^_]]{4}"));//true
System.out.println("23_F".matches("\\w&&[^-]{4}"));//false

}
}

三、ArrayList

1.ArrayList的构造与添加方法

ArrayList构造方法:
public ArrayList();创建一个空的对象集合

ArrayList添加方法:
public boolean add(E e);//将指定元素追加到此集合的末尾
public void add(int index, E element);//在此集合的指定位置插入指定的元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package ArrayList;
import java.util.ArrayList;
/*
ArrayList构造方法:
public ArrayList();创建一个空的对象集合

ArrayList添加方法:
public boolean add(E e);//将指定元素追加到此集合的末尾
public void add(int index, E element);//在此集合的指定位置插入指定的元素

*/
public class case1 {
public static void main(String[] args) {
//创建一个空的对象
ArrayList<String> array=new ArrayList<String>();
//在集合末尾追加元素
System.out.println(array.add("Hello"));//返回的是boolean类型
array.add("world");
array.add("java");
//在集合指定位置添加元素
array.add(1,"good");
array.add(4,"people");
//输出集合
System.out.println("array : "+array);
}
}

2、ArrayList的常用方法

public boolean remove(Object o);删除指定元素,返回删除是否成功

public E remove(int index);删除指定索引位置上的元素,并返回删除元素

public E set(int index, E element);修改指定位置处的元素,返回被修改的元素

public E get(int index);返回指定索引处的元素

public int size();返回集合中元素的个数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package ArrayList;
//ArrayList的常用方法
/*
public boolean remove(Object o);删除指定元素,返回删除是否成功
public E remove(int index);删除指定索引位置上的元素,并返回删除元素
public E set(int index, E element);修改指定位置处的元素,返回被修改的元素
public E get(int index);返回指定索引处的元素
public int size();返回集合中元素的个数
*/
import java.util.ArrayList;
public class case2 {
public static void main(String[] args) {
ArrayList<String> array=new ArrayList<String>();
//添加元素
array.add("hello");
array.add("java");
array.add("world");
array.add("hello");
array.add("world");
array.add("hello");
array.add("hello");
array.add("hello");
array.add("java");
//删除元素
array.remove(0);
array.remove("world");
//修改元素
array.set(1,"begin");
//获取元素
System.out.println("下标为2的元素为:"+array.get(2));
//获取集合元素个数
System.out.println("集合中元素个数为:"+array.size());
System.out.println("array:"+array);
}
}

四、面向对象编程

类之间的关系

在软件系统中,类不是孤立存在的,类与类之间存在各种关系。根据类与类之间的耦合度从弱到强排列,UML 中的类图有以下几种关系:依赖关系、关联关系、聚合关系、组合关系、泛化关系和实现关系。其中泛化和实现的耦合度相等,它们是最强的。

1.依赖关系

依赖(Dependency)关系是一种使用关系,它是对象之间耦合度最弱的一种关联方式,是临时性的关联。在代码中,某个类的方法通过局部变量、方法的参数或者对静态方法的调用来访问另一个类(被依赖类)中的某些方法来完成一些职责。

在 UML 类图中,依赖关系使用带箭头的虚线来表示,箭头从使用类指向被依赖的类。

2.关联关系

关联(Association)关系是对象之间的一种引用关系,用于表示一类对象与另一类对象之间的联系,如老师和学生、师傅和徒弟、丈夫和妻子等。关联关系是类与类之间最常用的一种关系,分为一般关联关系、聚合关系和组合关系。我们先介绍一般关联。

关联可以是双向的,也可以是单向的。在 UML 类图中,双向的关联可以用带两个箭头或者没有箭头的实线来表示,单向的关联用带一个箭头的实线来表示,箭头从使用类指向被关联的类。也可以在关联线的两端标注角色名,代表两种不同的角色。

3.聚合关系

聚合(Aggregation)关系是 关联关系的一种,是强关联关系,是整体和部分之间的关系,是 has-a 的关系。

聚合关系也是通过成员对象来实现的,其中成员对象是整体对象的一部分,但是成员对象可以脱离整体对象而独立存在。例如,学校与老师的关系,学校包含老师,但如果学校停办了,老师依然存在。

在 UML 类图中,聚合关系可以用带空心菱形的实线来表示,菱形指向整体。

4.组合关系

组合(Composition)关系也是 关联关系的一种,也表示类之间的整体与部分的关系,但它是一种更强烈的聚合关系,是 cxmtains-a 关系。

在组合关系中,整体对象可以控制部分对象的生命周期,一旦整体对象不存在,部分对象也将不存在,部分对象不能脱离整体对象而存在。例如,头和嘴的关系,没有了头,嘴也就不存在了。

在 UML 类图中,组合关系用带实心菱形的实线来表示,菱形指向整体。

5.泛化(继承)关系

泛化(Generalization)关系是对象之间耦合度最大的一种关系,表示一般与特殊的关系,是父类与子类之间的关系,是一种继承关系,是 is-a 的关系。

在 UML 类图中,泛化关系用带空心三角箭头的实线来表示,箭头从子类指向父类。在代码实现时,使用面向对象的继承机制来实现泛化关系。

6.实现关系

实现(Realization)关系是接口与实现类之间的关系。在这种关系中,类实现了接口,类中的操作实现了接口中所声明的所有的抽象操作。

在 UML 类图中,实现关系使用带空心三角箭头的虚线来表示,箭头从实现类指向接口。

异同分析

  • 聚合和组合的区别:
    聚合是个体离开了整体,依然可以存在.
    组合是个体和整体不可以分开,个体不能离开整体单独存在.

  • 依赖,关联 和聚合,组合的区别:
    依赖,关联 : 类之间的关系是在同一层次上.
    聚合,组合: 类之间的关系表现为整体和部分

在代码层面的体现方式

  • 依赖:
    一般情况下,依赖关系体现为:局域变量、方法的形参(返回值)、对静态方法的调用。

  • 关联:

    一般情况下,关联(组合,聚合都是关联关系的一种)关系体现为:成员变量

1.继承

在Java语言中,一个类继承另一个类需要使用关键字extends,关键字extends的使用方法如下:

1
public class child extends parent {}

Java只支持单继承,即一个类只有一个父类,子类在继承父类的方法后,创建子类对象的同时也会调用父类的构造方法,其中会先执行父类的构造方法,再执行子类的构造方法。子类继承父类后,可以调用父类创建好的方法和属性。

继承的好处与弊端:

好处:

  • 提高了代码的复用性
  • 提高了代码的维护性

弊端:

  • 继承让类与类之间产生了关系,类的耦合性增强了。当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性

继承中变量的访问特点

在子类方法中访问一个变量

  1. 子类局部范围内找
  2. 子类成员范围找
  3. 父类成员范围找
  4. 如果没有就会报错(不考虑父亲的父亲)

super关键字

super关键字和this关键字的用法相似

  • this代表本类对象的引用
  • super代表父类存储空间的标识(可以理解为父类对象引用)
关键字 访问成员变量 访问构造方法 访问成员方法
this this.成员变量 访问本类成员变量 this(……) 访问本类构造方法 this.成员方法(……)访问本类成员方法
super super.成员变量 访问父类成员变量 super(……) 访问父类构造方法 super.成员方法(……)访问父类成员方法

instanceof关键字

该关键字可以用来判断是否一个类实现了某个接口或者用来判断一个实例化对象是否属于一个类,其返回类型是布尔类型

1
2
3
4
5
6
7
8
9
10
class Quadrangle{ }
class Square extends Quadrangle{ }
class Circular{ }
public class Demo{
public static void main(String[] args){
Quadrangle q=new Quadrangle();
Square s=new Square();
System.out.println(q instanceof Square);
}
}

继承中构造方法的访问特点

子类中所有的构造方法默认都会访问父类中无参的构造方法

  • 子类会继承父类中的数据,可能还会使用父类中的数据。所以,子类初始化前,一定要先完成父类数据的初始化
  • 每一个子类构造方法的第一条语句默认为: super()

如果父类中没有无参构造方法,只有带参构造方法,有两种解决方案:

  • 通过使用super关键字去显式的调用父类的带参构造方法
  • 在父类中提供一个无参构造方法

继承中成员方法的访问特点

通过子类对象访问一个方法

  1. 子类成员范围中找
  2. 父类范围成员找
  3. 如果都没有则会报错(不考虑父亲的父亲)

方法重写:

  • 子类中出现了和父类一样的方法声明

应用:

  • 当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,既沿袭了父类的功能,又定义了子类特有的内容

@Override

  • 是一个注解
  • 可以帮助我们检查重写方法的方法声明的正确性

注意事项:

  • 私有方法不能被重写(父类私有成员子类不能继承)
  • 子类方法的访问权限不能更低(public>默认>私有)

Java继承中注意事项:

  • Java中类只支持单继承,不支持多继承
  • Java中类支持多层继承

修饰符

1.包的概述与使用

其实就是文件夹,作用是对类进行分类管理

包的定义格式:

package 包名;(多级包.分开)

带包的Java类编译和执行

  • 手动建包:按照以前的格式编译java文件 javac xxx.java

    ​ 手动创建包 在x盘建立文件夹com然后在com下建立文件夹itheima

    ​ 把class文件放到包的最里面 把xxx.class文件放到com.itheima这个文件夹下

    ​ 带包执行 java com.itheima.xxx

  • 自动建包:javac-d .xxx.java java com.itheima.xxx

2.导包

使用不同包下的类时,使用的时候要写类的全路径,写起来太麻烦了,为了简化带包的操作,Java提供了导包的功能

导包的格式:

import 包名;

3.修饰符

修饰符 同一个类中 同一个包中子类无关类 不同包的子类 不同包的无关类
private
默认
protected
public

状态修饰符:

final 最终 可以修饰成员方法,成员变量,类

final修饰的特点

  • 修饰方法:表明该方法是最终方法,不能被重写
  • 修饰变量:表明该变量是常量,不能再次被赋值
  • 修饰类:表明该类是最终类,不能被继承

final修饰局部变量

  • 变量是基本数据类型:final修饰指的是基本数据类型的数据值不能发生改变
  • 变量是引用类型:final修饰指的是引用类型的地址值不能改变,但是地址里面的内容是可以改变的

static 静态 可以修饰成员方法和成员变量

static修饰的特点

  • 被类的所有对象共享(这也是判断我们是否使用静态关键字的条件)
  • 可以通过类名调用(也可以通过对象调用)

static访问特点

非静态的成员方法

  • 能访问静态的成员变量
  • 能访问非静态的成员变量
  • 能访问静态的成员方法
  • 能访问非静态的成员方法

静态的成员方法

  • 能访问静态的成员方法
  • 能访问静态的成员变量

2.多态

同一个对象,在不同时刻表现出来的不同的形态

举例:

猫 cat= new 猫();

动物 animal =new 猫();

这里猫在不同时刻表现出来了不同的形态,这就是多态。

多态的前提和体现

  • 有继承/实现关系
  • 有方法重写
  • 有父类引用指向子类对象

多态中成员的访问特点

成员变量:编译看左边,执行看左边

成员方法:编译看左边,执行看右边(因为成员方法有重写,而成员变量没有重写)


多态的好处与弊端

好处:提高了程序的扩展性

具体实现:定义方法的时候,使用父类型作为参数,将来使用的时候,使用具体的子类型参与操作

弊端:不能使用子类的特有功能

执行顺序:先执行父类的静态语句(哪句语句在前先执行)再执行子类的静态语句(哪句语句在前先执行),再执行父类的代码块、成员属性赋值(哪个在前哪个先执行),后执行父类的构造方法,最后执行子类的代码块、成员属性赋值(哪个在前哪个先执行),后执行子类的构造方法。


多态中的转型

  • 向上转型

    从子到父

    父类引用指向子类对象

  • 向下转型

    从父到子

    父类引用转化为子类对象

    1
    2
    3
    4
    5
    6
    7
    8
    //eat()方法已重写
    //playGame()方法未被重写
    Animal a=new Cat();//向上转型
    a.eat();
    //向下转型
    Cat c=(Cat)a;
    c.eat();
    c.playGame();

    抽象类

    在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类

    抽象类的特点:

    • 抽象类和抽象方法必须使用abstract关键字修饰

      ​ public abstract class 类名 {}

      ​ public abstract void eat();

    • 抽象类中不一定有抽象方法,但有抽象方法的一定是抽象类

    • 抽象类不能实例化对象

    • 抽象类可以参考多态的形式,通过子类对象实例化,这叫抽象类多态

    • 抽象类的子类

      ​ 要么重写抽象类中的所有抽象方法

      ​ 要么该子类也必须是一个抽象类

    抽象类的成员特点:

    • 成员变量

      ​ 可以是变量,也可以是常量

    • 构造方法

      ​ 有构造方法,但是不能实例化,构造方法用于子类访问父类数据的初始化

    • 成员方法

      ​ 可以有抽象方法:限定子类必须完成某些任务

      ​ 也可以有非抽象类方法:提高代码复用性


    接口:

    接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用

    Java中的接口更多的体现在对行为的抽象

    接口的特点:

    • 接口用关键字interface修饰

      ​ public interface 接口名 {}

    • 类实现接口用implements表示

      ​ public class 类名 implements 接口名{}

    • 接口不能实例化

      ​ 接口实例参照多态的方式,通过实现类对象实例化,这叫接口多态

      ​ 多态的形式:具体类多态,抽象类多态,接口多态

      ​ 多态的前提:有继承或者实现关系;有方法重写;有父(类/接口)引用指向(子/实现)类对象

    • 接口的实现类

      ​ 要么重写接口中的所有抽象类方法,要么是抽象类

    接口的成员特点:

    • 成员变量

      ​ 只能是常量,默认修饰符:public static final

    • 构造方法:

      ​ 接口没有构造方法,因为接口主要是对行为进行抽象的,是没有具体存在

      ​ 一个类如果没有父类,默认继承超类Object类

    • 成员方法:

      ​ 只能是抽象方法,默认修饰符:public abstract


    类和接口之间的关系:

    • 类和类的关系

      ​ 继承关系,只能单继承,但是可以多层继承

    • 类和接口之间的关系

      ​ 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口

    • 接口和接口之间的关系

      ​ 继承关系,可以单继承,也可以多继承

    抽象类和接口的区别:

    • 成员区别

      ​ 抽象类 变量,常量;有构造方法;有抽象方法,也有非抽象方法

      ​ 接口 常量;抽象方法

    • 关系区别

      ​ 类与类 继承,单继承

      ​ 类与接口 实现,可以单实现,也可以多实现

      ​ 接口与接口 继承,单继承,多继承

    • 设计理念区别

      ​ 抽象类 对类抽象,包括属性,行为

      ​ 接口 对行为抽象,主要是行为

    抽象类是对事物的抽象,而接口是对行为的抽象

3.内部类

1.类名作为形参和返回值

  • 方法的形参是类名,其实需要的是该类的对象
  • 方法的返回值值是类名,其实返回的是该类的对象

2.抽象类名作为形参和返回值

  • 方法的形参是抽象类名,其实需要的是该抽象类的子类对象
  • 方法的返回值是抽象类名,其实返回的是该抽象类的子类对象

3.接口名作为形参和返回值

  • 方法的形参是接口名,其实需要的是该接口的实现类对象
  • 方法的返回值是接口名,其实返回的是该接口的实现类对象

内部类:就是在一个类中定义一个类。

内部类的定义格式:

1
2
3
4
5
public class 类名{
修饰符 class 类名{

}
}

内部类的访问特点:

  • 内部类可以直接访问外部类的成员,包括私有
  • 外部类要访问内部类的成员,必须创建对象

成员内部类不止可以在外部类中使用,在其他类中也可以使用。语法如下:

1
2
外部类 outer =new 外部类();
外部类.内部类 inter=new outer.new 内部类();
  • 如果在外部类和非静态方法之外实例化内部类对象,需要使用“外部类.内部类”的形式指向该对象的类型。
  • 内部类对象会依赖于外部类对象,除非已经存在一个外部类对象,否则类中不会出现内部类对象。

使用this关键字获取内部类和外部类之间的引用

​ 如果在外部类中定义的成员变量与内部类的成员变量名称相同,可以使用this关键字

1
2
3
4
5
6
7
8
9
10
11
12
public class TheSameName{
private int x=7;
private class Inter{
int x=9;
public void work(){
int x=11;
x++;//局部变量x++
this.x++;//内部类中的成员变量x++
TheSameName.this.x++;//外部类中的成员变量x++
}
}
}

匿名内部类:

匿名内部类是在创建对象时才会编写类体的一种写法,匿名类的特点是“现用现写”,其语法如下:

1
2
3
new 父类/接口{
子类实现的内容
};

注意:最后一个大括号之后有分号

匿名类的特点:

  • 匿名类不能写构造方法
  • 匿名类不能定义静态的成员变量
  • 如果匿名类创建的对象没有赋值给任何引用变量,会导致该对象用完一次后就会被Java虚拟机销毁。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//使用匿名类创建一个抽象狗类的对象
public abstract class Dog{
String Color;
public abstract void move();
public abstract void call();
}

public class Demo{
public void main(String[] args){
Dog temp=new Dog(){
public void move(){
System.out.println("四腿狂奔");
}
public void call(){
System.out.println("嗷呜~");
}
};
temp.Color="灰色";
temp.move();
temp.call();
}
}

说明:匿名内部类编译以后,会产生以“外部类名$序号”为名称的.class文件,序号以1~n排列,分别代表1-n个匿名内部类。

4.Object类

Java中所有类都直接或者间接继承了java.lang.Object类.Object类是比较特殊的类,它是所有类的父类,是Java类中的最高层类。

Object类的常用方法:

方法 说明
getClass() 它会返回对象执行时的Class实例,此外也可以通过此实例调用getName()方法取得类名。getClass().getName();
toString() 将一个对象返回以字符串的形式,它会返回一个String实例。
equals() “==”比较的是两个对象引用地址是否相等,而equals()比较的是两个对象的实际内容。

toString()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Main {
public static void main(String[] args) {

//toString 返回对象的字符串表示形式
//包名 + 类名 + 地址值
Object obj = new Object();
String str1 = obj.toString();
System.out.println(str1); //java.lang.Object@723279cf
System.out.println(obj); //直接打印也可以获得相同结果
/*
* System:类名
* out:静态变量
* System.out:获取打印的对象
* print():方法,会调用toString
* 参数:表示打印的内容
* */
//如果要打印对象属性,可以重写toString方法
}
}

equals()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.Objects;
public class Student {
private String name;
private int age;
//IDEA中使用 alt + insert,快捷重写equals方法
@Override
public boolean equals(Object o) {
if (this == o) return true; //同一个对象,直接true
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o; //强转成子类对象
return age == student.age && Objects.equals(name, student.name); //进行对比
}
}

五、常用API

1.Math类

Math包括执行基本数学运算的方法,如基本指数,对数,平方根和三角函数。

调用形式:

Math.数学方法

也存在一些常用数字常量 如:Math.PI Math.E

1.三角函数方法:

1
2
3
4
5
6
7
8
9
public static double sin(double a); //返回角的正弦值
public static double cos(double a);// 返回角的余弦值
public static double tan(double a); //返回角的正切值
public static double asin(double a);// 返回一个值的反正弦
public static double acos(double a); //返回一个值的反余弦
public static double atan(double a); //返回一个值的反正切
public static double toRadians(double a); //将角度转化为弧度
public static double toDegrees(double a); //将弧度转化为角度

2.指数函数方法:

1
2
3
4
5
6
public static double exp(double a);//获取e的a次方,即取e^a的值
public static double log(double a);//用于取自然对数,即lna的值
public static double log10(double a);//用于取底数为10的a的对数
public static double sqrt(double a);//用于取a的算术平方根,其中a的值不能为负值
public static double cbrt(double a);//用于取a的立方根
public static double pow(double a,double b);//用于取a的b次方

3.取整函数方法

1
2
3
4
5
public static double ceil(double a);//返回大于等于参数的最小整数
public static double floor(double a);//返回小于等于参数的最小整数
public static double rint(double a);//返回与参数最接近的整数,若存在两个同样接近的数,取偶数
public static int round(double a);//四舍五入
public static long round(double a);//四舍五入,然后强制转换为长整型

4.取最大值、最小值、绝对值方法

1
2
3
public static double max(double a,double b);//取最大值
public static int/long/float/double min(double a,double b);//取最小值
public static int/long/float/double abs(double a);//返回int/long/float/double类型参数的绝对值

2.BigInteger类

BigInteger类的数字范围比Integer类的大得多,BigInteger类支持任意精度的整数,使用BigInteger类进行运算可以准确无误地表示任何大小的整数值并且不会丢失任何信息。语法如下:

1
2
BigInteger twoInstance =new BigInteger("2");
//参数2的双引号不能省略,因为参数是以字符串的形式存在的

BigInteger类的常用运算方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public BigInteger add(BigInteger val);//做加法运算
public BigInteger subtract(BigInteger val);//做减法运算
public BigInteger multiply(BigInteger val);//做乘法运算
public BigInteger divide(BigInteger val);//做除法运算
public BigInteger remainder(BigInteger val);//做取余运算
public BigInteger[] divideAndRemainder(BigInteger val);//用数组返回余数和商,数组的第一个值为商,第二个值为余数
public BigInteger pow(int exponent);//进行取参数的exponent次方操作
public BigInteger negate();//取相反数
public BigInteger shiftLeft(int n);//数字左移n位,若n为负数,则右移
public BigInteger shiftRight(int n);//数字右移n位,若n为负数,则左移
public BigInteger and(BigInteger val);//与操作
public BigInteger or(BigInteger val);//或操作
public int compareTo(BigInteger val);//做数字比较操作
public boolean equals(Object x);//当参数x是BigInteger类并且数值与对象实例的数值相等时,返回true
public BigInteger max(BigIntegr val);//返回较大的数值
public BigInteger min(BigInteger val);//返回较小的数值

样例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import java.math.BigInteger;
public class Demo2 {
public static void main(String[] args){
BigInteger x=new BigInteger("222222222");
BigInteger y=new BigInteger("111111111");
BigInteger z=x.add(y);//加法
BigInteger c=x.subtract(y);//减法
BigInteger v=x.multiply(y);//乘法
BigInteger u=x.divide(y);//除法
BigInteger r=x.remainder(y);//取余
BigInteger Max=x.max(y);//取最大值
BigInteger Min=x.min(y);//取最小值
BigInteger yu=x.and(y);//与运算
BigInteger huo=x.or(y);//或运算
BigInteger oppo=x.negate();//取相反数
BigInteger exp=x.pow(2);//进行取参数的exponent次方操作
int ans=x.compareTo(y);//做数字的比较操作,大于参数返回正整数,等于返回0,小于返回负整数
BigInteger left=x.shiftLeft(1);//将数字左移n位,如果n为负数,做右移操作
BigInteger right=x.shiftRight(1);//将数字右移n位,如果n为负数,做左移操作
BigInteger []arr=x.divideAndRemainder(y);//用数组返回余数和商,结果数组中第一个值为商,第二个值为余数
boolean flag=x.equals(12);//当参数x是BigInteger类型的数字并且数值与对象实例的数值相等时,返回true,否则返回false
System.out.println("加法运算后的结果:"+z);
System.out.println("减法运算后的结果:"+c);
System.out.println("乘法运算后的结果:"+v);
System.out.println("除法运算后的结果:"+u);
System.out.println("取余运算后的结果:"+r);
System.out.println("两者中的最大值为:"+Max);
System.out.println("两者中的最小值为:"+Min);
System.out.println("与操作后的结果:"+yu);
System.out.println("或操作后的结果:"+huo);
System.out.println("相反数为:"+oppo);
System.out.println("参数的2次方结果为:"+exp);
System.out.println("做比较操作后的结果为:"+ans);
System.out.println("做左移1位后的结果:"+left);
System.out.println("做右移1位后的结果:"+right);
System.out.println("商:"+arr[0]+" 余数:"+arr[1]);
System.out.println("判断参数与12是否相等:"+flag);
}
}

3.System类

System类是JDK提供的系统类,该类是用final修饰的,所以不允许继承,System类提供了很多系统层面的操作方法,并且这些方法全部都是静态的。以下为System类常用方法:

方法 功能描述
currentTimeMillis() 返回以毫秒为单位的当前时间
exit(int status) 通过启动虚拟机的关闭序列,终止当前正在运行的Java虚拟机,此方法从不正常返回,可以将变量作为一个状态码,根据惯例,非零的状态码表示非正常终止;0表示正常终止
Mapgetenv() 返回一个不能修改的当前系统环境的字符串映射视图
getenv(String name) 获取指定的环境变量值
getProperties() 确定当前的系统属性
getProperty(String key) 获取用指定键描述的系统属性
setIn(InputStream in) 重新分配“标准输入流”

System类提供了标准输入、标准输出和错误输出流,即System类提供了三个静态对象:in、out、err.在控制台输出字符串,有两种方法:

  • 不会自动换行的print()方法
1
System.out.print("Hello");
  • 会自动换行的println()方法
1
System.out.println("书籍是人类进步的阶梯");

注意事项:

  • System.out.println(“\n”); //会打印两个空行
  • System.out.print(); //没有参数会报错

计时

利用System.currentTimeMillis()方法可以用来记录程序的运行时间

1
2
3
4
5
6
7
8
9
10
11
public class SystemTimeDemo {
public static void main(String[] args){
long start=System.currentTimeMillis();//程序开始记录时间
String str=null;
for(int i=0;i<10000;i++){
str+=i;
}
long end=System.currentTimeMillis();//记录循环结束时间
System.out.println("循环用时为:"+(end-start)+"毫秒");
}
}

4.Arrays类

Array类包含于用于操作数组的各种方法

方法名 说明
public static String toString(int[] a) 返回指定数组的内容的字符串表达形式
public static void sort(int[] a) 按照数字顺序排列指定的数组
1
2
3
4
5
6
7
8
9
10
11
import java.util.Arrays;
public class Main {
public static void main(String[] args){
//定义一个数组
int[] arr={20,69,80,57,13};
System.out.println("排序前:"+Arrays.toString(arr));
//排序
Arrays.sort(arr);
System.out.println("排序后:"+Arrays.toString(arr));
}
}

工具类的设计思想:

  • 构造方法用private修饰
  • 成员用public static修饰

5.基本类型包装类

将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据

常用的操作之一:用于基本数据类型和字符串之间的转换

基本数据类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

Integer类的概述和使用

Integer:包装一个对象中的原始类型int的值

方法名 说明
public Integer(int value) 根据int值创建Integer对象(过时)
public Integer(String s) 根据String值创建Integer对象(过时)
public static Integer valueOf(int i) 返回指定的int值的Integer实例
public static Integer valueOf(String s) 返回一个保存指定值的Interger对象String
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Main {
public static void main(String[] args){
Integer i1=new Integer(100);//过时
System.out.println(i1);
Integer i2=new Integer("100");//过时 字符串里面的内容必须由数字组成
System.out.println(i2);
Integer i3=Integer.valueOf(100);
System.out.println(i3);
Integer i4=Integer.valueOf("100");//字符串里面的内容必须由数字组成
System.out.println(i4);
}
}

int和String的相互转换

1.int →String类型

  • public static String valueOf(int i):返回int类型参数的字符串表示形式,该方法是String类中的方法。

2.String →int类型

  • public static int parseInt(String s);将字符串解析成int类型,该方法是Integer类中的方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//int -- String 的相互转换
public class Main {
public static void main(String[] args){
int number=100;
///int ->String
//方式1 +
String s=""+number;
System.out.println(s);
//方式2 public static String valueOf(int i)
String s2=String.valueOf(number);
System.out.println(s2);
System.out.println("----------------");
//String -> int
String str="1000";
//方式1 String -> Integer -> int
Integer temp=Integer.valueOf(str);
int x=temp.intValue();
System.out.println(x);
//方式2 public static int parseInt(String s)
int y=Integer.parseInt(str);
System.out.println(y);
}
}

6.日期时间类

1.Date类

Date类用于表示日期和时间,使用该类表示时间需要使用其构造方法来创建对象,其构造方法以及说明表如下。

构造方法 方法说明
Date() 分配Date对象并初始化对象,以表示分配它的时间(精确到毫秒)
Date(long date) 分配Date对象并初始化此对象,以表示自标准基准时间(即1970年1月1日00:00:00GMT)起经过指定毫秒数date后的时间
1
2
long timeMillis=System.currentTimeMillis();  //当前系统时间所经历的毫秒数
Date date =new Date(timeMillis);

创建Date对象使用的是long型整数,而不是double型,这主要是因为double类型可能会损失精度。

​ Date类的常用方法以及说明

方法 说明
after(Date when) 测试当前日期是否在指定日期之后
before(Date when) 测试当前日期是否在指定日期之前
getTime() 获取自1970年1月1日00:00:00GMT开始到现在所经过的毫秒数
setTime(long time) 设置当前Date对象所表示的日期时间值,该值用以1970年1月1日00:00:00GMT以后time毫秒的时间点

案例1:

​ 获取当前的日期和时间

1
2
3
4
5
6
7
8
9
10
package APIDemp;
import java.util.Date;
public class DateDmo {
public static void main(String[] args){
Date date=new Date();//创建现在的日期
long value=date.getTime();//获取毫秒数
System.out.println("日期: "+date);
System.out.println("到现在所经历的毫秒数:"+value);
}
}

日期时间格式化

​ DateFormat类是日期时间格式化子类的抽象类,可以按照指定的格式对日期或时间进行格式化。DateFormat类提供了很多类方法,以获得基于默认或给定语言环境和多种格式化风格的默认日期时间Formatter,格式化主要包括四种风格:

SHORT:完全为数字,如12.13.52或3:30pm

MEDIUM:较长,如Jan 12, 1952

LONG:更长,如January 12,1953或3:39:32pm

FULL:完全指定,如Tuesday、April 12、1952AD或3:30:34pm PST

另外,使用DateFormat类还可以自定义日期时间的格式。要格式化一个当前语言环境下的日期,首先要创建一个DateFormat类的一个对象,由于它是抽象类,因此可以使用getDateInstance()进行创建,语法如下:

1
DateFormat df = DateFormat.getDateLnstance();

使用getDateInstance()方法获取的是所在国家或地区的标准日期格式,而使用getTimeInstance()获取的是当前所在国家或地区的时间格式,而使用getDateTimeInstance()获取的是当前国家或者地区的日期时间格式。

​ DateFormat类的常用方法及其说明

方法 说明
format(Date date) 将一个Date对象实例格式化为日期/时间字符串
getCalendar() 获取与此日期时间/时间格式器关联的日历
getDateInstance() 获取日期格式器,该格式器具有默认语言环境的默认格式化风格
getTimeInstance() 获取时间格式器,该格式器具有默认语言环境的默认格式化风格
getDateTimeInstance() 获取日期/时间格式器,该格式器具有默认语言环境的默认格式化风格
getInstance() 获取为日期/时间使用SHORT风格的默认日期/时间格式器
parse(String source) 将字符串解析成一个日期,并返回这个日期的Date对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package APIDemp;
import java.text.DateFormat;
import java.util.Date;
public class DateDmo {
public static void main(String[] args){
// DateFormat df=DateFormat.getTimeInstance(DateFormat.LONG);
// DateFormat df=DateFormat.getDateInstance(DateFormat.LONG);
DateFormat df=DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG);
DateFormat df2=DateFormat.getInstance();
Date date=new Date();
System.out.println(df.format(date));
//System.out.println(df.getCalendar());
System.out.println(df.format(new Date()));
System.out.println(df2.format(new Date()));

}
}

​ 由于DateFormat类是一个抽象类,不能new创建实例对象。因此,出来使用getXXXinstance()方法创建其对象,还可以使用其子类,如SimpleDateFormat类,该类是一个以与语言环境相关的方式来格式化和分析日期的具体类,它允许进行格式化(日期→文本)、分析(文本→日期)和规范化。

​ SimpleDateFormat的格式化字符

字母 日期或时间元素 类型 示例
G Era标示符 Text AD
y Year 1996
M 年中的月份 Month July;Jul;07
w 年中的天数 Number 27
W 月份中的天数 Number 2
D 年中的天数 Number 179
d 月份中的天数 Number 10
F 月份中的星期 Number 2
E 星期中的天数 Text Tuesday;Tue
t Am/pm的标记 Text PM
H 一天中的小时数(0~23) Number 0
h am/pm中的小时数(1~12) Number 12
k 一天中的小时数(1~24) Number 24
K am/pm中的小时数(0~11) Number 0
m 小时中的分钟数 Number 30
s 分钟中的秒数 Number 55
S 毫秒数 Number 978
z 时区 General time zone PST
Z 时区 RFC 822 time zone -800

​ 常用时间格式

日期时间 对于的格式
2021/10/25 yyyy/MM/dd
2021.10.25 yyyy.MM.dd
2021-09-14 13:20:43 yyyy-MM-dd HH:mm:ss
2021年10月21日 10时21分05秒 星期日 yyyy年MM月dd日 HH时mm分ss秒 EEEE
下午3时 ah时
今年已经过去了297天 今年已经过去了D天

案例2:

​ 以中文形式打印当前的日期和时间

1
2
3
4
5
6
7
8
9
10
11
12
package APIDemp;
import java.text.DateFormat;
import java.util.Date;
import java.text.SimpleDateFormat;
public class DateDmo {
public static void main(String[] args){
DateFormat df=new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒 EEEE");
System.out.print("各位观众大家好,现在是:");
System.out.print(df.format(new Date()));
System.out.println(", 欢迎大家收看新闻");
}
}

7.集合类

​ 集合可以看成一个容器,Java中提供了不同的集合类,这些类有不同的存储对象,同时提供了相应的方法,以方便用户对集合进行遍历、添加、删除和查找指定的对象。集合类与数组的不同之处是:数组长度是固定的,集合的长度是可变的;数组常用来存储基本类型的数据,集合用来存放对象的引用。常用的集合有List集合、Set集合和Map集合,其中List集合与Set集合继承了Collection接口,各接口还提供了不同的实现类。

1.Collection接口

​ Collection接口是层次结构中的根接口,构成Collection的单位称为元素。Collection接口通常不能直接使用,但该接口提供了添加元素、删除元素、管理数据的方法。由于List接口与Set接口都继承了Collection接口,因此这些方法对List集合与Set集合是通用的。Collection接口的常用方法如下:

方法 功能描述
add(E e) 将指定对象添加到集合中
remove(Object o) 将指定的对象从该集合中移除
isEmpty() 返回boolean值,用于判断当前集合是否为空
iterator() 返回在此Collection的元素上进行迭代的迭代器,用于遍历集合中的对象
size() 返回int型值,获取该集合中元素的个数

​ 通常遍历集合,都是通过迭代器来实现

案例:

​ 向购物车添加商品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package APIDemp;
import java.util.*;
public class CollectionDemo {
public static void main(String[] args){
Collection<String>list=new ArrayList<>();//实例化集合对象
list.add("《Java从入门到精通》");
list.add("《零基础学Java》");
list.add("《Java编程思想》");
Iterator<String> it=list.iterator();//创建迭代器
while(it.hasNext()){//判断是否有下一个元素
String str=(String)it.next();//获取集合中的元素
System.out.println(str);
}
}
}

2.List集合

1.List接口

​ List接口继承了Collection接口,因此包含Collection接口中的所有方法。此外List接口还定义了两个重要的方法:

方法 说明
get(int index) 获得指定索引位置的元素
set(int index,Object obj) 将集合中指定索引位置的对象修改为指定的对象

2.List接口的实现类

  • ArrayList类实现了可变的数组,允许保存所有元素,包括null,并可以根据索引位置对集合进行快速的随机访问。缺点是向指定的索引位置插入对象或者删除对象的速度较慢。
  • LinkedList类采用链表的结构保存对象。这种结构的优点是便于向集合中插入和删除元素。需要向集合中插入、删除对象时,使用LinkedList类实现的List集合的效率较高;但对于随机访问集合中的元素,使用LinkedList类实现List集合的效率较低。
1
2
List<E> list = new ArrayList<>();
List<E> list2 = new LinkedList<>();

注意:与数组相同,集合的索引也是从0开始的。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package APIDemp;
import java.util.*;
public class ListDemo {
public static void main(String[] args){
List<String> list = new ArrayList<>();//创建集合对象
//向集合中添加元素
list.add("a");
list.add("b");
list.add("c");
list.set(0,"d");//修改0索引位置上的元素值
int i=(int)(Math.random()*list.size());//获得0~2的随机数
System.out.println("随机获取集合中的元素:"+list.get(i));
list.remove(i);//将指定索引位置中的元素从集合中移除
System.out.println("集合中剩下的元素分别是:");
for(int j=0;j<list.size();j++){
System.out.println(list.get(j));
}
}
}

3.Set集合

​ Set集合中的对象不按特定的方式排序,只是简单地把对象加入到集合中,但Set集合中不能包含重复对象。Set集合由Set接口和Set接口的实现类组成。因此包含Collection接口的所有方法。

​ Set接口常用的实现类有HashSet类和TreeSet类,简述如下:

  • HashSet类实现Set接口,由哈希表(实际上是一个HashMap实例)支持。它不保证Set集合的迭代顺序,特别是它不保证该顺序永恒不变。此类允许使用元素null。
  • TreeSet类不仅实现了Set接口,还实现了java.util.SortSet接口,因此TreeSet类实现的Set集合在遍历集合按照自然顺序递增排序,也可以按照指定比较器递增排序,即可以通过比较器对用TreeSet类实现的Set集合中的对象进行排序。

​ TreeSet类增加的方法

方法名称 功能描述
first() 返回此Set集合中当前第一个(最低)元素
last() 返回此Set集合中当前最后一个(最高)元素
comparator() 返回对此Set集合中的元素是进行排序的比较器。如果该集合采用的是自然顺序排序,则返回null
headSet(E toElenment) 返回一个新的Set集合,新集合是toElement对象(不包含)之前的所有对象
subSet(E fromElement,E fromElement) 返回一个新的Set集合,新集合是fromElement对象(包含)与fromElement对象(不包含)之间的所有对象
tailSet(E fromElement) 返回一个新的Set集合,新集合包含fromElement对象(包含)之后的所有对象

案例:

​ 使用TreeSet类完成自然(升序)排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package APIDemp;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
import java.util.Scanner;
public class SetDemo {
public static void main(String[] args){
TreeSet<Integer> temp=new TreeSet<>();
temp.add(12);
temp.add(21);
temp.add(-3);
temp.add(6);
temp.add(85);
//temp.add(12); 重复元素不会被添加
System.out.println("集合中的第一个元素:"+temp.first());
System.out.println("集合中的最后一个元素:"+temp.last());
Iterator<Integer> it=temp.iterator();
System.out.print("temp中的集合元素为:");
while(it.hasNext()){
System.out.print(it.next()+" ");
}
System.out.println();
//headSet
Set<Integer> temp2=temp.headSet(12);//截取当前元素前面的元素,不包含当前元素
Iterator<Integer> it2=temp2.iterator();
while(it2.hasNext()){
System.out.print("temp2中的集合元素为:");
while(it2.hasNext()){
System.out.print(it2.next()+" ");
}
}
System.out.println();
//tailSet
Set<Integer> temp3=temp.tailSet(12);//截取当前元素后面的元素,包含当前元素
Iterator<Integer> it3=temp3.iterator();
while(it3.hasNext()){
System.out.print("temp3中的集合元素为:");
while(it3.hasNext()){
System.out.print(it3.next()+" ");
}
}
System.out.println();
//subSet
Set<Integer> temp4=temp.subSet(6,21);//截取两个元素之前的元素,包含前面元素,不包含后面元素
Iterator<Integer> it4=temp4.iterator();
while(it4.hasNext()){
System.out.print("temp4中的集合元素为:");
while(it4.hasNext()){
System.out.print(it4.next()+" ");
}
}
System.out.println();
}
}

4.Map集合

​ Map集合没有继承Collection接口,其提供的是key到value的映射。Map集合中不能包含相同的Key,每个key只能映射一个value.key还决定了存储对象在映射中的存储位置,但不是由key对象本身决定的,而是通过一种”散列技术”进行处理,产生一个散列码的整数值。散列码通常用作一个偏移量,该偏移量对应分配给映射的内存区域的起始位置,从而确定存储对象在映射中的存储位置。Map集合包含Map接口和Map接口的所有实现类。

1.Map接口

​ Map接口提供了将key映射到值的对象。一个映射不能包含重复的key,每个key最多只能映射到一个值。除集合的常用方法外,Map接口还提供了下图所示方法:

​ Map常用方法

方法 功能描述
put(K key,V value) 向集合中添加所指定的key与value的映射关系
containsKey(Object key) 如果此映射中包含指定key的映射关系,则返回true
contaninsValue(Object value) 如果此映射将一个或者多个key映射到指定值,则返回true
get(Object key) 如果存在指定的key对象,则返回该对象的值,否则返回null
keySet() 返回该集合中的所有key对象形成的Set集合
values() 返回该集合中的所有值对象形成的Collectin集合
remove(Object key) 从映射中删除与Key相关的映射
putAll(Map t) 将来自特定映像的所有元素添加给该映像
clear() 删除所有映射

2.Map接口的实现类

  • SortedMap接口 用来保持键的有序顺序

    方法 功能描述
    Comparator comparator() 返回对关键字进行排序时使用的比较器,如果使用Comparable接口的compareTo() 方法进行关键字比较,则返回null
    Object firstKey() 返回映射中第一个(最低)关键字
    Object lastKey() 返回映射中最后一个(最高)关键字
    SortedMap subMap(Object fromKey,Object toKey) 返回从fromKey(包括)到toKey(不包括)范围内的元素的SortedMap视图(子集)
    SortedMap headMap(Object toKey) 返回SortedMap的第一个视图,其内各元素的key都小于toKey
    SortedMap tailMap(Object fromKey) 返回SortedMap中的最后一个视图,里面元素的key都大于或者等于fromKey
  • HashMap是基于哈希表的Map接口实现,此实现提供所有可选的映射操作,并允许使用null值和null键,但必须保证键的唯一性。HashMap类通过哈希表对其内部的映射关系进行快速查找。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

  • TreeMap类不仅实现了Map接口,还实现了java.util.SortMap接口,因此集合中的映射关系具有一定的顺序。但在添加、删除、定位映射关系时,TreeMap类比HashMap类性能较差。由于TreeMap类实现的Map集合中的映射关系是根据键对象按照一定的顺序排列的,因此不允许键对象是null。

六、泛型

泛型:是JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型 它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,顾名思义,就是将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型,这种参数类型可以用在类、方法和接口中,分别称为泛型类、泛型方法、泛型接口

泛型定义格式:

  • <类型> : 指定一种类型的格式,这里的类型可以看成是形参
  • <类型1,类型2>:指定多种类型的格式,多种类型用逗号隔开。这里的类型可以看成是形参
  • 将来具体调用时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型

泛型的好处:

  • 把运行时期的问题提前到了编译期间
  • 避免了强制类型转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package Generic;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;

/*
需求:Collection集合存储字符串并遍历
*/
public class GenericDemo {
public static void main(String[] args) {
//创建集合对象
// Collection c = new ArrayList();
Collection<String> c = new ArrayList<String>();

//添加元素
c.add("hello");
c.add("world");
c.add("java");
// c.add(100);

//遍历集合
//Iterator it = c.iterator();
Iterator<String> it = c.iterator();
while(it.hasNext()){
// Object obj = it.next();
// System.out.println(obj);
// String s = (String)it.next(); //ClassCastException
String s = it.next(); //ClassCastException
System.out.println(s);
}
}
}

泛型类

泛型类的定义格式:

  • 格式:修饰符 class 类名 <类型> { }

  • 范例:public class Generic { }

    ​ 此处的T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package Generic;
//泛型类
public class Generic <T> {
private T t;

public T getT() {
return t;
}

public void setT(T t) {
this.t = t;
}
public static void main(String[] args) {

Generic<String> g1 = new Generic<String>();
g1.setT("李清霞");
System.out.println(g1.getT());
Generic<Integer> g2 = new Generic<Integer>();
g2.setT(30);
System.out.println(g2.getT());
Generic<Boolean> g3 = new Generic<Boolean>();

g3.setT(true);
System.out.println(g3.getT());

}
}

  • 泛型类中的泛型成员不能直接实例化。它们的实例化必须通过相关方法的参数来传递给他们。
1
2
3
4
5
6
7
8
9
10
public class Main <T>{
private T[] array; //这里不能直接newT[]来实例化array
public void setArray(T[] tt){
array = tt;
}

public T[] getArray() {
return array;
}
}
  • 同一个泛型类,如果实例化时给予的实际具体类型不一样,那么这些实例类型是不兼容的,不能相互赋值。

泛型方法

泛型方法的定义格式:

  • 格式:修饰符 <类型> 返回值类型 方法名 (类型 变量名){ }
  • 范例:public void show( T t) { }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package Generic;
//泛型方法
public class Generic {
public <T> void show(T t){
System.out.println(t);
}
public static void main(String[] args) {
Generic g = new Generic();
g.show("李清霞");
g.show(100);
g.show(true);
g.show(100.100);
}
}

泛型接口

泛型接口的定义格式:

  • 格式:修饰符 interface 接口名 <类型> { }
  • 范例:public interface Generic { }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package Generic;
//泛型接口
public interface Generic <T>{
void show(T t);
}


package Generic;

public class Genericlmpl<T> implements Generic<T> {
@Override
public void show(T t) {
System.out.println(t);
}
}


package Generic;
class GenericDemo {
public static void main(String[] args) {
Generic<String> g1 = new Genericlmpl<String>();
g1.show("李清霞");

Generic<Integer> g2 = new Genericlmpl<Integer>();
g2.show(100);

}
}

类型通配符

为了表示各种泛型List的父类,可以使用通配符

  • 类型通配符:<?>
  • List<?>:表示元素类型未知的List,它的元素可以匹配任何的类型
  • 这种带通配符的List仅表示它是各种泛型List的父类,并不能把元素添加到其中

如果说我们不希望任何List<?>是任何泛型List的父类,只希望它代表某一类泛型List的父类,可以使用类型通配符的上限

  • 类型通配符上限:<? extends 类型>
  • List<? extends Number>:它表示的类型是Number或者其子类型

除了可以指定类型通配符的上限,也可以指定类型通配符的下限

  • 类型通配符下限:<? super 类型>
  • List<? super Number>:它表示的类型是Number或者其父类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package Generic;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
class GenericDemo {
public static void main(String[] args) {
//类型通配符: <?>
List<?> list1 = new ArrayList<Object>();
List<?> list2 = new ArrayList<Number>();
List<?> list3 = new ArrayList<Integer>();
System.out.println("-------");

//类型通配符上限: <? extends 类型>
//List<? extends Integer> list4 = new ArrayList<Number>(); 报错 Integer是Number的子类
List<? extends Number> list4 = new ArrayList<Number>();
List<? extends Number> list5 = new ArrayList<Integer>();
System.out.println("--------");

//类型通配符下限: <? super 类型>
List<? super Integer> list6 = new ArrayList<Number>();
List<? super Number> list7 = new ArrayList<Number>();
//List<? super Number> list8 = new ArrayList<Integer>(); 报错 Integer是Number的子类


}
}

可变参数

可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的

  • 格式:修饰符 返回值类型 方法名(数据类型… 变量名){ }
  • 范例:public static int sum(int… a){ }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package Generic;
//可变参数
public class ArgsDemo1 {
public static void main(String[] args) {
System.out.println(sum(20,20));
System.out.println(sum(20,20,30));
System.out.println(sum(20,20,30,40));
System.out.println(sum(20,20,30,40,50));
System.out.println(sum(20,20,30,40,50,60));
}

public static int sum(int... a){//a相当于一个数组
int sum = 0;
for(int i:a){
sum += i;
}
return sum;
}
}

可变参数注意事项:

  • 这里的变量其实是一个数组
  • 如果一个方法有多个参数,包含可变参数,可变参数要放最后
1
public static int sum(int b,int... a){ }

可变参数的使用

Arrays工具类中有一个静态方法:

  • public static List asList(T… a); 返回由指定数组支持的固定大小的列表
  • 返回的集合不能做增删操作,可以做修改操作

List接口中有一个静态方法:

  • public static List of(E… elements); 返回包含任意数量元素的不可变列表
  • 返回的集合不能做增删改操作

Set接口中有一个静态方法:

  • public static Set of(E… elements); 返回一个包含任意数量元素的不可变集合
  • 在给元素时,不能给重复的元素
  • 返回的集合不能做增删操作,没有修改的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package Generic;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

public class ArgsDemo2 {
public static void main(String[] args) {
//public static <T> List<T> asList(T... a); 返回由指定数组支持的固定大小的列表
List<String> list = Arrays.asList("hello", "world", "java");
// list.add("javascript"); UnsupportedOperationException
// list.remove("java"); UnsupportedOperationException
list.set(1, "你好");
System.out.println(list);

//public static <E> List<E> of(E... elements); 返回包含任意数量元素的不可变列表
List<String> list2 = List.of("hello", "world", "java", "world");
// list2.add("你好"); UnsupportedOperationException
// list2.remove("world"); UnsupportedOperationException
// list2.set(2,"你好"); UnsupportedOperationException
System.out.println(list2);

//public static <E> Set<E> of(E... elements); 返回一个包含任意数量元素的不可变集合
// Set<String> set = Set.of("hello","world","java","world"); ImmutableCollections$SetN.<init>
Set<String> set = Set.of("hello","world","java");
// set.add("你好"); UnsupportedOperationException
// set.remove("hello"); UnsupportedOperationException
System.out.println(set);
}
}

七、异常

异常就是代表程序出现的问题。其父类是 Throwable。其下两个子类,Error 和 Exception。Error 代表的是系统级别的错误(严重问题),是SUN公司自己用的。而 Exception 代表程序可能出现的问题。Exception 分为 RuntimeException 和其他异常。其中,RuntimeException 是运行时异常,编译阶段不会被检测出来,编译阶段 Java 不会执行代码,只会检查语法是否错误,或者做一些性能优化编译时异常更多是提醒程序员检查本地信息,运行时异常是代码逻辑出错而导致程序出现的问题。

idea 当中使用 Ctrl + Alt + T 进行 try catch 包裹。

Error:代表的系统级别错误(属于严重问题)

Exception:异常,代表程序可能出现的问题,通常用Exception以及它的子类来封装程序出现的问题。

运行时异常:RuntimeException及其子类,编译阶段不会出现异常提醒。运行时出现的异常(如:数组索引越界异常)

编译时异常:除了Exception及其子类,其他都是编译时异常。编译阶段就会出现异常提醒的。(如:日期解析异常)

编译阶段:java不会运行代码,只会检查语法错误,或者做一些性能的优化

1
2
3
4
5
6
Java文件
⬇ Javac命令
字节码文件
⬇ Java命令
运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package myException;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ExceptionDemo1 {
public static void main(String[] args) throws ParseException {

//编译时异常(在编译阶段,必必须手动处理,否则代码报错)
String time = "2023年12月18日";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
Date date = sdf.parse(time);
System.out.println(date);

//运行时异常(在编译阶段是不需要处理的,是代码运行时出现的异常)
int[] arr = {1,2,3,4,5};
System.out.println(arr[5]);

}
}



异常的作用

  • 是用来查询bug的关键参考信息。
  • 异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况(看异常的发生位置可以从下往上读)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Student {
int age;
String name;

void setAge(int age) {
if(age < 18 || age > 40) {
throw new RuntimeException(); //抛出异常
}
this.age = age;
}

}

public class Main {
public static void main(String[] args) {
Student s1 = new Student();
s1.setAge(19);
s1.setAge(17); //RuntimeException
}
}

异常的处理方式

异常的常见处理方式有:

  1. JVM默认处理。
  2. 捕获异常。
  3. 抛出异常。

其中,抛出主要是告诉调用者出错了。而捕获主要是为了不让程序停止

JVM默认处理

把异常的名称,异常原因以及异常出现的位置等信息用红色字体打印在控制台上。并且此时的程序停止,代码不再执行。

捕获异常

目的是让异常出现的时候,让程序继续执行。基本语法为:

1
2
3
4
5
try {
可能出现异常的代码;
} catch (异常类名 变量名){
异常的处理代码;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Main {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4};
try {
//可能出现异常的代码
System.out.println(arr[10]);
//这里会创建ArrayIndexOutOfBoundsException的对象
//与catch中的e对比,看看类型是否匹配,匹配了,就让程序继续进行
} catch (ArrayIndexOutOfBoundsException e) {
//出现异常后该如何处理
System.out.println("索引越界了");
}
System.out.println("看看我执行了吗");

//最终执行的结果为:
//索引越界了
//看看我执行了吗
}
}

关于捕获异常的四个注意点:

  • 如果 try 中没有遇到问题,会执行 try 当中的所有代码,不会执行 catch 的代码。也就是说,catch 当中的代码只有出现了了异常才会执行。

  • 如果 try 中遇到多个问题,如果第一个问题能够被顺利捕获,则接下来 try 中代码便不会执行。最佳解决方案是写多个 catch 捕获多个问题(一行一个 catch或者一行中利用 | 连接),并且,如果异常之间有父子类关系的话,父类一定要写在下面

  • 如果 try 中遇到的问题没有被捕获,则使用 JVM 默认处理异常的方式进行处理。

  • 如果 try 中遇到了问题,try 下面的其他代码便不会执行了,直接跳到 catch,但如果没有 catch 与之匹配,则按照 JVM 默认处理异常的方式进行处理。

  • 赋值运算符(=)的关联性是从右到左,因此若一条赋值语句的左右两边都出现异常,则会先抛出等号右边的异常。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    //exceptions2.ExDemo3.java
    package exceptions2;

    public class ExDemo3 {

    public static void method1() {
    int[] arrayOfNumbers = new int[10];
    try
    {
    arrayOfNumbers[10] = 11;
    }
    catch (NumberFormatException e1)
    {
    System.out.println("NumberFormatException => " + e1.getMessage());
    }
    catch (IndexOutOfBoundsException e2)
    {
    System.out.println("IndexOutOfBoundsException => " + e2.getMessage());
    }
    }

    public static void method2() {
    try
    {
    int array[] = new int[10];
    array[10] = 30 / 0;
    }
    catch (ArithmeticException e)
    {
    System.out.println(e.getMessage());
    }
    catch (ArrayIndexOutOfBoundsException e)
    {
    System.out.println(e.getMessage());
    }
    }

    public static void main(String[] args) {
    // TODO Auto-generated method stub
    method2();
    }
    //调用method2方法时左边数组越界,右边除数为0,出现两个异常,但由于=的关联性是从右到左,因此会抛出右边的异常
    }

抛出异常

  • throws:写在方法定义处,表示声明一个异常。告诉调用者,使用本方法可能会有哪些异常。如果是编译时异常,必须要写,如果是运行时异常,可以不写。
  • throw:写在方法内,结束方法。手动抛出异常对象,交给调用者。方法中下面的代码不在执行了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class Main {
public static void main(String[] args) {
int[] arr = null;
int sum = 0;

//处理时使用try catch捕获
try {
sum = getSum(arr);
} catch (NullPointerException e) {
System.out.println("空指针异常");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("索引异常");
}


System.out.println(sum);
}

//定义一个方法求总和
public static int getSum(int[] number)
throws NullPointerException, ArrayIndexOutOfBoundsException { //可以声明异常
if(number == null) {
throw new NullPointerException(); //也可以抛出异常
}
if(number.length == 0) {
throw new ArrayIndexOutOfBoundsException();
}
int result = 0;
for(int index : number) {
result += index;
}
return result;
}
}

异常中的常见方法

方法名称 说明
public String getMessage() 返回此 throwable 的详细消息字符串
public String toString() 返回此可抛出的简短描述
public void printStackTrace() 把异常的错误信息输出在控制台,但不停止虚拟机的运行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Main {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4};
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println(e.getMessage()); //Index 10 out of bounds for length 4
//以上语句会打印异常的消息

//java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 4
System.out.println(e.toString());

e.printStackTrace(); //打印操作,但实际不会停止虚拟机,因为第16行的测试代码会被成功打印
}

System.out.println("看看我执行了吗");

}
}

自定义异常

自定义异常的目的是为了让报错信息更加见名知意。步骤如下:

  1. 定义异常类(编译时异常继承 Exception,运行时异常继承 RuntimeException)。
  2. 写继承关系。
  3. 空参构造。
  4. 带参构造。
  • 如果try catch 语句中有返回值,并且语句中含有finally关键字,则return 后仍然会执行finally中的语句,即finally关键字包围的语句一定执行。return的如果是基本数据类型,则在finally块中不可以修改已返回的数据,如果是引用类型,则可以改变。

八、I/O流

8.1File

File类概述和构造方法

File:它是文件和目录路径名的抽象表示

  • 文件和目录是可以通过File封装成对象的
  • 对于File而言,其封装的并不是一个真正存在的文件,仅仅只是一个路径名。它可以是存在的,也可以是不存在的。将来是要通过具体的操作把这个路径的内容转化为具体存在的
方法名 说明
File(String pathname) 通过将给定的路径名字符串转化为抽象路径名来创建新的File实例
File(String parent,String child) 从父路径名字符串和子路径名字符串创建新的File实例
File(File parent,String child) 从父抽象路径名和子路径名字符串创建新的File实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package File;

import java.io.File;

public class FileDemo1 {
public static void main(String[] args) {
//File(String pathname) 通过将给定的路径名字符串转化为抽象路径名来创建新的File实例
File f1 = new File("D:\\IDEA\\java.txt");
System.out.println(f1);

//File(String parent,String child) 从父路径名字符串和子路径名字符串创建新的File实例
File f2 = new File("D:\\IDEA","java.txt");
System.out.println(f2);

//File(File parent,String child) 从父抽象路径名和子路径名字符串创建新的File实例
File f3 = new File("D:\\IDEA");
File f4 = new File(f3,"java.txt");
System.out.println(f4);
}
}

File类创建功能

方法名 说明
public boolean createNewFile() 当具有该名称的文件不存在时,创建一个由该抽象路径命名的新空文件
public boolean mkdir() 创建由此抽象路径命名的目录
public boolean mkdirs() 创建由此抽象路径命名的目录,包括任何必需但不存在的父目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package File;

import java.io.File;
import java.io.IOException;

public class FileDemo2 {
public static void main(String[] args) throws IOException {
//需求1:在D:\\IDEA目录下创建一个文件java.txt
/*
如果文件不存在,就创建文件,返回true
如果文件存在,就不创建文件,返回false
*/
File f1 = new File("D:\\IDEA\\java.txt");
System.out.println(f1.createNewFile());
System.out.println("--------");
//需求2:在D:\\IDEA目录下创建一个目录JavaSE
/*
如果目录不存在,就创建目录,返回true
如果目录存在,就不创建目录,返回false
*/
File f2 = new File("D:\\IDEA\\JavaSE");
System.out.println(f2.mkdir());
System.out.println("--------");
//需求3:在D:\\IDEA目录下创建一个多级目录JavaWEB\\HTML
/*
如果目录不存在,就创建目录,返回true
如果目录存在,就不创建目录,返回false
*/
File f3 = new File("D:\\IDEA\\JavaWEB\\HTML");
System.out.println(f3.mkdirs());
System.out.println("--------");
//需求4:在D:\\IDEA目录下创建一个文件Javase.txt
File f4 = new File("D:\\IDEA\\javase.txt");
//System.out.println(f4.mkdir());
System.out.println(f4.createNewFile());
}
}

File类判断和获取功能

方法名 说明
public boolean isDirectory() 测试此抽象路径名表示的File是否为目录
public boolean isFile() 测试此抽象路径名表示的File是否为文件
pblic boolean exists() 测试此抽象路径名表示的File是否存在
public String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串
public String getPath() 将此抽象路径名转换为路径字符串
public String getName() 返回此抽象路径名表示的文件或者目录的名称
public String[] list() 返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
public File[] listFiles() 返回此抽象路径名表示的目录中的文件和目录中的File对象数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package File;

import java.io.File;

public class FileDemo4 {
public static void main(String[] args) {
//创建一个File对象
File f1 = new File("protect\\java.txt");
System.out.println(f1.isDirectory());
System.out.println(f1.isFile());
System.out.println(f1.exists());

System.out.println(f1.getAbsolutePath());//绝对路径
System.out.println(f1.getPath());//相对路径
System.out.println(f1.getName());
System.out.println("--------");

File f2 = new File("D:\\IDEA");
String[] strArray = f2.list();
for(String str:strArray){
System.out.println(str);
}
System.out.println("--------");
File [] fileArray = f2.listFiles();
for(File file : fileArray){
//System.out.println(file);//会调用其toString方法
//System.out.println(file.getName());
if(file.isFile()){
System.out.println(file.getName());
}
}

}
}

File删除功能

方法名 说明
public boolean delete() 删除由此抽象路径名表示的文件或目录

绝对路径和相对路径的区别:

  • 绝对路径:完整的路径名,不需要任何其他信息就可以定位它所表示的文件。例如:D:\IDEA\java.txt
  • 相对路径:必须使用取自其他路径名的信息进行解释。例如:IDEA\java.txt

删除目录时的注意事项:

  • 如果一个目录中有内容(目录、文件),不能直接删除,必须先删除目录中的内容,最后才能删除目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package File;

import java.io.File;
import java.io.IOException;

public class FileDemo3 {
public static void main(String[] args) throws IOException {
//创建一个文件
// File f1= new File("D:\\IDEA\\java.txt");
//需求1:在当前模块目录下创建java.txt文件
File f1 = new File("java.txt");
System.out.println(f1.createNewFile());

//需求2:删除当前模块目录下的java.txt文件
System.out.println(f1.delete());
System.out.println("--------");
//需求3:在当前目录下创建itcast目录
File f2 = new File("D:\\IDEA\\itcast");
System.out.println(f2.mkdir());

//需求4:删除当前模块下的itcast目录
System.out.println(f2.delete());
System.out.println("--------");

//需求5:在当前模块下创建一个目录itcast,然后在itcast目录下创建一个文件java.txt
File f3 = new File("D:\\IDEA\\itcast");
System.out.println(f3.mkdir());
File f4 = new File("D:\\IDEA\\itcast\\java.txt");
System.out.println(f4.createNewFile());
System.out.println("--------");

//需求6:删除当前模块的目录itcast以及里面的文件java.txt
/*
如果该目录下存在文件,则需要先将目录下的文件删除才能再将该目录删除
*/
System.out.println(f4.delete());
System.out.println(f3.delete());
}
}

案例:遍历目录

需求:给定一个路径(D:\IDEA),请通过递归完成遍历该目录下的所有内容,并把所有内容的绝对路径输出在控制台

九、反射

反射允许对封装类的字段、方法和构造函数的信息进行编程访问

IDEA中crtl+p能够弹出括号内需要的参数类型

字段(成员变量):获取修饰符、名字、类型,赋值/获取值

构造方法:获取修饰符、名字、形参,创建对象

成员方法:获取修饰符、名字、形参、返回值,抛出的异常、获取注解、允许方法

9.1获取class对象

获取class对象的三种方式:

  • Class.forName(“全类名”);
  • 类名.class
  • 对象.getClass();

源代码阶段:Java文件 A.java → class文件 A.class 第一种方式

加载阶段:将A.class放到内存中 第二种方式

运行阶段:A a = new ( );第三种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package Reflect;

public class MyReflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
/*
获取class对象的三种方式:
1 Class.forName("全类名");
2 类名.class
3 对象.getClass();
*/

//1.Class.forName() 最为常用
// 包名+类名
Class clazz = Class.forName("Reflect.Student");
System.out.println(clazz);

//2.类名.class 当作参数来进行传递
Class clazz2 = Student.class;
System.out.println(clazz2);

//3.对象.getClass() 当我们有了这个对象时才可以使用
Student s = new Student();
Class clazz3 = s.getClass();
System.out.println(clazz3);
System.out.println(clazz == clazz2);
System.out.println(clazz == clazz3);

}
}

Java中万物皆对象,Java中有Class用来描述字节码文件,这个类的对象就是字节码文件的对象,有Constructor来描述构造方法,这个类的对象就表示这个构造方法的对象,Field用来描述字段(成员变量),这个类的对象就是成员变量的对象,Method用来描述成员方法,这个类的对象就是成员方法的对象

9.2利用反射获取构造方法

Class类中用于获取构造方法的方法

  • Constructor<?>[] getConstructors();返回所有公共构造方法对象的数组
  • Constructor<?>[] getDeclaredConstructors(); 返回所有构造方法对象的数组
  • Constructor getConstructor(Class<?>…parameterTypes);返回单个公共构造方法对象
  • Constructor getDeclaredConstructor(Class<?>…parameterTypes);返回单个构造方法对象

Constructor类中用于创建对象的方法

  • T newInstance(Object… initargs);根据指定的构造方法创建对象
  • setAccessible(boolean flag);设置为true,表示取消访问检查
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package Reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;

public class MyReflectDemo2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
/*
**Class类中用于获取构造方法的方法**
- Constructor<?>[] getConstructors();返回所有公共构造方法对象的数组
- Constructor<?>[] getDeclaredConstructors(); 返回所有构造方法对象的数组
- Constructor<T> getConstructor(Class<?>...parameterTypes);返回单个公共构造方法对象
- Constructor<T> getDeclaredConstructor(Class<?>...parameterTypes);返回单个构造方法对象
*
**Constructor类中用于创建对象的方法**

- T newInstance(Object... initargs);根据指定的构造方法创建对象
- setAccessible(boolean flag);设置为true,表示取消访问检查
*/

//1.获取class字节码文件对象
Class clazz = Class.forName("Reflect.Student");

//2.获取构造方法
Constructor[] cons = clazz.getConstructors();
for(Constructor con : cons){
System.out.println(con);
}

Constructor[] cons2 = clazz.getDeclaredConstructors();
for(Constructor con : cons2){
System.out.println(con);
}

Constructor con1 = clazz.getDeclaredConstructor();
System.out.println(con1);

Constructor con2 = clazz.getDeclaredConstructor(String.class);
System.out.println(con2);

Constructor con3 = clazz.getDeclaredConstructor(int.class);
System.out.println(con3);

Constructor con4 = clazz.getDeclaredConstructor(String.class,int.class);
System.out.println(con4);

int modifiers = con4.getModifiers(); // public: 1 protected: 4 private: 2 获取权限修饰符
System.out.println(modifiers);

Parameter[] parameters = con4.getParameters();//获取参数
for(Parameter parameter : parameters){
System.out.println(parameter);
}

//暴力反射,表示临时取消权限校验
con4.setAccessible(true);
Student stu = (Student)con4.newInstance("张三",14);
System.out.println(stu);

}
}

9.3利用反射获取成员变量

Class类中用于获取成员变量的方法

  • Field[] getFields();返回所有公共成员变量对象的数组
  • Field[] getDeclaredFields();返回所有成员变量对象的数组
  • Field getField(String name);返回单个公共成员变量对象
  • Field getDeclaredField(String name);返回单个成员变量对象

Filed类中用于创建对象的方法

  • void set(Object obj,Object value);赋值
  • Object get(Object obj);获取值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package Reflect;

import java.awt.*;
import java.lang.reflect.Field;

public class MyReflectDemo3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
/*
**Class类中用于获取成员变量的方法**

- Field[] getFields();返回所有公共成员变量对象的数组
- Field[] getDeclaredFields();返回所有成员变量对象的数组
- Field getField(String name);返回单个公共成员变量对象
- Field getDeclaredField(String name);返回单个成员变量对象

**Filed类中用于创建对象的方法**

- void set(Object obj,Object value);赋值
- Object get(Object obj);获取值
*/

//1.获取class字节码文件对象
Class clazz = Class.forName("Reflect.Student");

//2.获取成员变量
//获取所有成员变量
Field[] fields = clazz.getFields();
for(Field field : fields){
System.out.println(field);
}

Field[] fields2 = clazz.getDeclaredFields();
for(Field field : fields2){
System.out.println(field);
}

//获取单个成员变量
Field gender = clazz.getField("gender");
System.out.println(gender);
Field name = clazz.getDeclaredField("name");
System.out.println(name);
Field age = clazz.getDeclaredField("age");
System.out.println(age);

//获取权限修饰符
int modifies = name.getModifiers();
System.out.println(modifies);
int modifies2 = gender.getModifiers();
System.out.println(modifies2);

//获取成员变量名
String n = name.getName();
System.out.println(n);

//获取数据类型
Class<?> type = name.getType();
System.out.println(type);

//获取成员变量的值
Student stu = new Student("张三",29);
//临时取消权限检查
name.setAccessible(true);
Object value = name.get(stu);
System.out.println(value);

//修改成员变量的值
name.set(stu,"李四");
System.out.println(stu);


}
}

9.4利用反射获取成员方法

Class类中用于获取成员方法的方法

  • Method[] getMethods(); 返回所有公共成员方法对象的数组,包括继承的
  • Method[] getDeclaredMethods();返回所有成员方法的数组,不包括继承的
  • Method getMethod(String name,Class… parameterTypes);返回单个公共成员对象方法
  • Method getDeclaredMethod(String name,Class… parameterTypes);返回单个成员方法

Method类中用于创建对象的方法

Object invoke(Object obj,Object… args); 运行方法

参数一:用obj对象调用方法

参数二:调用方法的传递参数(如果没有就不写)

返回值:方法的返回值(如果没有就不写)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package Reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class MyReflectDemo4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
/*
**Class类中用于获取成员方法的方法**

- Method[] getMethods(); 返回所有公共成员方法对象的数组,<mark>包括继承的</mark>
- Method[] getDeclaredMethods();返回所有成员方法的数组,==不包括继承的==
- Method getMethod(String name,Class<T>... parameterTypes);返回单个公共成员对象方法
- Method getDeclaredMethod(String name,Class<T>... parameterTypes);返回单个成员方法

**Method类中用于创建对象的方法**

Object invoke(Object obj,Object... args); 运行方法
参数一:用obj对象调用方法
参数二:调用方法的传递参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)
*/

//1.获取class字节码文件对象
Class clazz = Class.forName("Reflect.Student");

//2.获取成员方法
//获取里面的所有公共成员方法对象(包括父类的所有公共方法)
Method[] methods = clazz.getMethods();
for(Method method:methods){
System.out.println(method);
}
//获取里面的所有的成员方法(不能获取父类的,但是可以获取本类中的私有方法)
Method[] methods1 = clazz.getDeclaredMethods();
for(Method method:methods1){
System.out.println(method);
}

//获取单一指定方法
Method method = clazz.getMethod("sleep");
System.out.println(method);
Method method1 = clazz.getDeclaredMethod("eat",String.class);
System.out.println(method1);

//获取修饰符
int modifies = method.getModifiers();
int modifies2 = method1.getModifiers();
System.out.println(modifies);
System.out.println(modifies2);

//获取方法名
String name = method1.getName();
System.out.println(name);

//获取形参
Parameter[] parameters = method1.getParameters();
for(Parameter parameter:parameters){
System.out.println(parameter);
}

//获取方法抛出的异常
Class[] exceptionTypes = method1.getExceptionTypes();
for(Class exceptionType:exceptionTypes){
System.out.println(exceptionType);
}

//方法运行
Student s = new Student();
//参数一s:表示方法的调用者
//参数二"水果":表示在调用方法时传递的实际参数
method1.setAccessible(true);
method1.invoke(s,"水果");

//获取方法的返回值
Object obj = method1.invoke(s,"水果");
System.out.println(obj);
}
}

反射的作用

  1. 获取一个类里面的所有信息,获取到之后,再执行其他的业务逻辑
  2. 结合配置文件,动态的创建对象并调用方法
上一篇:
动态规划
下一篇:
图论