JAVA学习笔记

一 java概述

1常用的dos命令

2java程序编写和执行过程

步骤1:编写,将java代码编写在.java结尾的源文件中

步骤2:编译,针对.java源文件进行编译操作。格式:javac 源文件名.java

步骤3:执行,针对编译后生成的字节码文件进行解释运行。格式: java 字节码文件名

3输出语句

System.out.println("hello,world!!中国");
System.out.print("hello,world!!中国");

println自动换行
print不换行

4java程序入口

public static void main(String[] args){
    
}

5源文件名与类名

如果这个类不是public,那么源文件名可以和类名不一致。但是不便于代码维护。

如果这个类是public,那么要求源文件名必须与类名一致。否则编译报错。

一个源文件中可以有多个类,编译后会生成多个.class字节码文件。

但是一个源文件只能有一个public的类。

6注释

单行注释

//这是输出语句

多行注释

/*
这是程序入口,多行注释
*/
多行注释不生成在字节码文件中

文档注释

/**
这是第一个java程序
@author cxxk
@version 1.0
*/

文档注释内容可以被JDK提供的工具 javadoc 所解析,生成一套以网页文件形式体现的该程序的说明文档。

7什么是JDK,JRE

  • JDK (Java Development Kit):是Java程序开发工具包,包含JRE 和开发人员使用的工具。

  • JRE (Java Runtime Environment) :是Java程序的运行时环境,包含JVM 和运行时所需要的核心类库

二变量与运算符

2.1变量

2.1.1整型数据

byte ,short,int,long

整型常量默认为int型

long a=123456l
long b=123456L
long型变量数据后面要加小写l或者大写L

2.1.2浮点型数据

float,double

浮点型常量默认为double型

float f1 =1.123f
float变量后面需要加F或f后缀
要求精度更高时,使用BigDecimal类

2.1.3字符类型

char   字符类型为单引号

表示形式1:
char c1 = 'a'
char c2 = '1'
char 后面只能跟一个字符
表示形式2:
char c3 = '\u0023'
跟一个UNICODE编码集
表示形式3:
char c4 = '\n'
表示一个转义字符
表示形式4:
char c5 = 43
表示一个asc码

2.1.4布尔类型

boolean

boolean b1 = true
boolean b2 = false
true 和 false 为小写

2.1.5数据类型之间的自动类型提升

char,byte,short -->int-->long-->float-->double
char,byte,short两两之间运算会自动转换为int型

long l1 = 123
这样写可以,因为常量123默认为int型,自动转换为long型
long l2 = 123123123123
这样写不行,常量123123123123默认为int型,超出了int所能表示的最大范围
float = 12.2
这样不行,浮点型常量12.2默认为double型
所以float后面必须加f后缀

2.1.6强制类型转换

long l = 12
int i = (int) l

double d = 1.1
int i = (int) d

语法:在转换的数字或变量前加(转换类型)

2.1.7string类

string是一个类,不是基本数据类型,string用" "表示

string str = "abc"
string是一个类,用双引号""
string和其他基本数据类型的连接
string str1 = str + 1 + 1.2 + 'a'
输出结果 abc11.2a
string 与其他基本数据类型的连接后还是string 类型
string str2 = "10"
int i = (int) str2
这么写是错误的,与python不一样
如果要将str2转化为int型,这么写:
int i1 = Integer.parseInt(str2)

2.2运算符

2.2.1算术运算符之自增,自减

i++,++i

i--,--i

int i = 1
int m = ++i
int n = i++
m = 2
n = 1
++i 先自增再赋值
i++ 先赋值再运算

自增不等于+1,自增不改变数据类型

byte b = 1
b = b + 1
编译报错,1为int型
b++
b = 2

2.2.2赋值运算符之+=,-=,*=,/=

+=,-=,*=,/=同自增自减,不改变原有数据类型

赋值语句bool类型

boolean x = false
if( x = true ){
}
条件满足
boolean y = true
if (y = false){
}
条件不满足

2.2.3逻辑运算符

& 和 &&的区别

boolean b1 = false
int x1 = 10
if (b1)&(x1++>0){
}
x1 = 11
&左边为false,仍要执行右边的操作

boolean b2 = flase
int x2 = 10
if (b2)&&(x2++>0){
}
x2 = 10
&&左边为false,不再执行右边的操作

2.2.4条件运算符

(条件表达式)? 表达式1 :表达式2

条件表达式的结果为true,返回表达式1的结果

条件表达式的结果为false,返回表达式2的结果

 int i = (1==2 ? 100 : 200);
    System.out.println(i);//200
    
 boolean marry = false;
	System.out.println(marry ? "已婚" : "未婚"  );//未婚

三流程控制语句

3.1分支结构

3.1.1scanner类

步骤1:导包 import java.util.Scanner;
步骤2:提供(或创建)一个Scanner类的实例
步骤3:调用Scanner类中的方法,获取指定类型的变量 (nextXxx())
步骤4:关闭资源,调用Scanner类的close()
 

//步骤1:导包 import java.util.Scanner;
import java.util.Scanner;
//步骤2:提供(或创建)一个Scanner类的实例
Scanner scan = new Scanner(System.in);
//scan为实例化对象名
//步骤3:调用Scanner类中的方法,获取指定类型的变量
String name = scan.next();

int age = scan.nextInt();

double weight = scan.nextDouble();

boolean isSingle = scan.nextBoolean();

char gender = scan.next().charAt(0);

//步骤4:关闭资源,调用Scanner类的close()
scan.close();

注意,没有提供获取char类型变量的方法。需要使用next().charAt(0)

3.1.2获取随机数

1. 可以使用Java提供的API:Math类的random() 
2. random()调用以后,会返回一个[0.0,1.0)范围的double型的随机数

3. 需求1:获取一个[0,100]范围的随机整数?
   需求2:获取一个[1,100]范围的随机整数?

4. 需求:获取一个[a,b]范围的随机整数?
   (int)(Math.random() * (b - a + 1)) + a

double d1 = Math.random();

int num1 = (int)(Math.random() * 101);   //[0.0,1.0) --> [0.0,101.0) --->[0,100]

int num2 = (int)(Math.random() * 100) + 1; //[0.0,1.0) --> [0.0,100.0) --->[0,99] ---> [1,100]

3.1.3 if-else语句

if(score == 100){
    System.out.println("奖励一辆跑车");
}else if(score > 80 && score <= 99){    //错误的写法:}else if(80 < score <= 99){
    System.out.println("奖励一辆山地自行车");
}else if(score >= 60 && score <= 80){
    System.out.println("奖励环球影城玩一日游");
}
//else{
//    System.out.println("胖揍一顿");
//}

3.1.4switch-case语句

int num = 1;
switch(num){
	case 0:
	    System.out.println("zero");
		break;
	case 1:
		System.out.println("one");
		break;
	case 2:
		System.out.println("two");
		break;
	case 3:
		System.out.println("three");
		break;
	default:
		System.out.println("other");
		//break;
}

如果没有break会一直往下执行

3.2循环结构

3.2.1for循环

for(;;){

}

for循环一般用于知道循环次数

3.2.2while循环

while(){

}

while循环一般用于不知道循环次数

3.2.3do-while循环

do{

}while()

do-while循环至少进行一次

3.2.4break和continue的使用

break跳出当前循环

continue跳出当次循环

四数组

4.1一维数组

4.1.1一维数组的声明

4.1.2一维数组的初始化

int[] arr = new int[]{1,2,3};

String[] str = new String[]{"cxk","cln","fcc"};

静态初始化,初始化和赋值在一起

int[] arr = new int[3];

String[] str = new String[5];

arr[0] = 1;

arr[1] = 2;

动态初始化,初始化和赋值分开

4.1.3一维数组的长度

int[] arr = new int[]{1,2,3};

int length = arr.length;//3

数组的length属性代表了数组的长度

4.1.4一维数组的遍历

int[] arr = new int[]{1,2,3};

for(int i =0;i<arr.length;i++){
    System.out.println(arr[i]);
}

4.1.5一维数组的默认值

动态初始化之后,整型数组默认值为0,浮点型默认值为0.0,布尔型默认为false,引用型默认为null,字符型默认为asc编码中的0

4.1.6一维数组的内存结构

int[] arr = new int[]{1,2,3};

在虚拟机栈中存放的是变量名arr,arr后面跟着是一个地址,

在堆中存放的是数据1,2,3,一片连续空间存放

sout(arr)输出的是地址

如果想要在堆中开辟一片新空间,必须new一下

4.2二维数组

4.2.1二维数组的声明

4.2.2二维数组的初始化

int[][] arr = new int[][]{{1,2,3},{4,5,6},{7,8,9}};

静态初始化

int[][] arr = new int[3][3];

int[][] arr = new int[3][];

动态初始化

4.2.3二维数组的长度

int[][] arr = new int[][]{{1,2,3},{4,5,6},{7,8,9}};

arr.length;//二维数组的长度,有几个一维数组

arr[0].length//具体某一个一维数组的长度

arr[1].length

arr[2].length

4.2.4二维数组的遍历

int[][] arr = new int[][]{{1,2,3},{4,5,6},{7,8,9}};


for(int i = 0;i<arr.length;i++){
    for(int j = 0;j<arr[i].length;j++){
        sout(arr[i][j]);
    }
}

4.2.5二维数组的默认值

4.2.6二维数组的内存结构

int[][] arr = new int[3][4];

虚拟机栈中存放arr,arr后面跟着一个地址,地址指向一个三行的数组,
该三行的数组每个元素都是一个地址,地址各自指向一个四行的数组,四行数组默认值为0

int[][] arr = new int[3][];

虚拟机栈中存放arr,arr后面跟着一个地址,地址指向一个三行的数组,
该三行数组的每个元素都是null


sout(arr)
sout(arr[0])
sout(arr[1])
sout(arr[2])
这些输出的均为地址

4.3Arrays工具类

导包
import java.util.Arrays;

判断两个数组是否相等

boolean i = Arrays.equals(arr1,arr2);

输出数组

sout(Arrays.toString(arr1);

二分查找

int index = Arrays.binarySearch(arr,12);

快排

Arrays.sort(arr);

填充

Arrays.fill(arr1,5);

五面向对象基础

5.1类和对象

5.1.1类和对象的概念

类:抽象的,概念上的定义

对象:具体的,类的一个一个的实例

面向对象完成具体功能的操作的三步流程:

步骤1:创建类,并设计类的内部成员(属性、方法)
步骤2:创建类的对象。比如:Phone p1 = new Phone();
步骤3:通过对象,调用其内部声明的属性或方法,完成相关的功能

5.1.2对象的内存解析

jvm的划分:

  • 虚拟机栈:以栈帧为基本单位,有入栈和出栈操作;每个栈帧入栈操作对应一个方法的执行;方法内的局部变量会存储在栈帧中。

  • 堆空间:new 出来的结构(数组、对象):① 数组,数组的元素在堆中 ② 对象的成员变量在堆中。

创建一个类的多个对象(比如 p1 p2 ),则每个对象都拥有当前类的一套 " 副本 " (即属
性)。当通过一个对象修改其属性时,不会影响其它对象此属性的值。
当声明一个新的变量使用现有的对象进行赋值时(比如 p3 = p1 ),此时并没有在堆空间中创
建新的对象。而是两个变量共同指向了堆空间中同一个对象。当通过一个对象修改属性时,
会影响另外一个对象对此属性的调用。
类、数组都是引用数据类型,引 用数据类型的变量中存储的是对象的地址,或者说指向堆中对象的首地址。

5.2成员变量(属性)

5.2.1成员变量vs局部变量

在方法体外,类体内声明的变量称为成员变量。
成员变量又被static分为类变量和实例变量
在方法体内部等位置声明的变量称为局部变量。
局部变量又分为形参(方法或构造器中声明的)、方法局部变量(方法中声明的)、代码块局部变量(代码块中声明的)
成员变量存储在堆中,局部变量存储在栈中
成员变量有默认值,局部变量没有,必须手动初始化。其中的形参比较特殊,靠实参给它初始化
修饰符 (1)实例变量:public,protected,private,final,volatile,transient等 (2)局部变量:final

5.3方法

5.3.1方法的声明

语法格式:

[ 修饰符 ] 返回值类型 方法名 ([ 形参列表 ])[ throws 异常列表 ]{
        方法体的功能代码
}
方法中可以调用类中的方法或属性,不可以在方法内部定义方法。
方法的内存解析:
方法 没有被调用 的时候,都在 方法区 中的字节码文件 (.class) 中存储。
方法 被调用 的时候,需要进入到 栈内存 中运行。方法每调用一次就会在栈中有一个 入栈 动作,即
给当前方法开辟一块独立的内存区域,用于存储当前方法的局部变量的值。
当方法执行结束后,会释放该内存,称为 出栈 ,如果方法有返回值,就会把结果返回调用处,如
果没有返回值,就直接结束,回到调用处继续执行下一条指令。

5.3.2方法的重载

在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可。
参数列表不同,意味着参数个数或参数类型的不同
重载的特点 :与修饰符、返回值类型无关,只看参数列表 且参数列表必须不同。 ( 参数个数或参
数类型 ) 。调用时,根据方法参数列表的不同来区别。

5.3.3可变个数形参的方法

格式:(int ... args)

public int sum(int... nums){
    int sum = 0;
    for (int i = 0; i < nums.length; i++) {
        sum += nums[i];
    }
    return sum;
}
方法的参数部分有可变形参,需要放在形参声明的最后
在一个方法的形参中,最多只能声明一个可变个数的形参

5.3.4方法的参数传递机制

如果形参是基本数据类型的变量,则将实参保存的数据值赋给形参。
如果形参是引用数据类型的变量,则将实参保存的地址值赋给形参。

5.4封装性

Java规定了4种权限修饰,分别是:private、缺省、protected、public。

体现:

> 场景1:私有化(private)类的属性,提供公共(public)的get和set方法,对此属性进行获取或修改
> 场景2:将类中不需要对外暴露的方法,设置为private
> 场景3:单例模式中构造器private的了,避免在类的外部创建实例。(放到static关键字后讲)

5.5构造器

语法格式:
 

[修饰符] class 类名{
    [修饰符] 构造器名(){
        // 实例初始化代码
    }
    [修饰符] 构造器名(参数列表){
        // 实例初始化代码
    }
}
说明:
1.当我们没有显式的声明类中的构造器时,系统会默认提供一个无参的构造器并且该构造器的修饰
符默认与类的修饰符相同
2.当我们显式的定义类的构造器以后,系统就不再提供默认的无参的构造器了。
111111
3.在类中,至少会存在一个构造器。
4. 构造器是可以重载的。
作用:
① 搭配上new,用来创建对象 ② 初始化对象的成员变量

六面向对象进阶

6.1this

this用在构造器中:

  • this():调用本类的无参构造器

  • this(实参列表):调用本类的有参构造器

  • this()和this(实参列表)只能声明在构造器首行。

 

6.2继承

class A extends B{}

Java中继承性的特点

  • 局限性:类的单继承性。后续我们通过类实现接口的方式,解决单继承的局限性。

  • 支持多层继承,一个父类可以声明多个子类。

6.3方法的重写

方法的重写:

  • 前提:类的继承关系

  • 子类对父类中同名同参数方法的覆盖、覆写。

6.4super

  • super可以调用的结构:属性、方法;构造器

  • super:父类的

  • super调用父类的属性、方法:

    • 如果子父类中出现了同名的属性,此时使用super.的方式,表明调用的是父类中声明的属性。

    • 子类重写了父类的方法。如果子类的任何一个方法中需要调用父类被重写的方法时,需要使用super.

  • super调用构造器:

    • 在子类的构造器中,首行要么使用了"this(形参列表)",要么使用了"super(形参列表)"。

    • 如果没写,默认super();

6.5多态

  • 多态的使用:虚拟方法调用。“编译看左边,运行看右边”。属性,不存在多态性。

  • 多态的弊端:不能调用子类特有的属性和方法,若想调用子类特有的属性和方法,就需要向下转型

  • 多态的逆过程:向下转型,使用强转符()。

    • 为了避免出现强转时的ClassCastException,建议()之前使用instanceOf进行判断。

public void feed(Pet pet){
        pet.eat();//pet实际引用的对象类型不同,执行的eat方法也不同
}


feed(dog);
feed(cat);



用父类当做方法形参,实际调用时传入的是子类

对象a  instanceOf  类型A

6.6object类

java.lang.Object是类层次结构的根类,即所有其它类的父类。每个类都使用 Object 作为超类。

如果一个类没有特别指定父类,那么默认则继承自Object类。

6.6.1toString()

  • Object中toString()调用后,返回当前对象所属的类和地址值。

  • 开发中常常重写toString(),用于返回当前对象的属性信息。

6.6.2equals()

  • == 既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型就是比较内存地址

  • equals的话,它是属于java.lang.Object类里面的方法,如果该方法没有被重写过默认也是==;我们可以看到String等类的equals方法是被重写过的,而且String类在日常开发中用的比较多,久而久之,形成了equals是比较值的错误观点。

  • 具体要看自定义类里有没有重写Object的equals方法来判断。

  • 通常情况下,重写equals方法,会比较类中的相应属性是否都相等。

6.6.3clone()

创建一个新的对象,返回为Object类型,强转

6.6.4getClass()

获取对象的运行时类型

6.7子类实例化的过程

七面向对象高级

7.1抽象类,抽象方法,abstract

public abstract class Animal {
    public abstract void eat();
}

抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。

抽象类中,也有构造方法,是供子类创建对象时,初始化父类成员变量使用的。

抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。

抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。

 abstract修饰类:
    > 此类称为抽象类
    > 抽象类不能实例化。
    > 抽象类中是包含构造器的,因为子类对象实例化时,需要直接或间接的调用到父类的构造器。
    > 抽象类中可以没有抽象方法。反之,抽象方法所在的类,一定是抽象类。

abstract修饰方法:
    > 此方法即为抽象方法
    > 抽象方法只有方法的声明,没有方法体。
    > 抽象方法其功能是确定的(通过方法的声明即可确定),只是不知道如何具体实现(体现为没有方法体)
    > 子类必须重写父类中的所有的抽象方法之后,方可实例化。否则,此子类仍然是一个抽象类。

7.2 接口interface

7.2.1概述

接口,用来定义一组规范、一种标准。

接口的本质是契约、标准、规范,就像我们的法律一样。制定好后大家都要遵守

7.2.2接口的声明

[修饰符] interface 接口名{
    //接口的成员列表:
    // 公共的静态常量
    // 公共的抽象方法
    
    // 公共的默认方法(JDK1.8以上)
    // 公共的静态方法(JDK1.8以上)
    // 私有方法(JDK1.9以上)
}

7.2.3接口的使用规则

1、类实现接口(implements)

接口不能创建对象,但是可以被类实现(implements ,类似于被继承)。

【修饰符】 class 实现类  implements 接口{
	// 重写接口中抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写
  	// 重写接口中默认方法【可选】
}

【修饰符】 class 实现类 extends 父类 implements 接口{
    // 重写接口中抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写
  	// 重写接口中默认方法【可选】
}

2、接口的多实现(implements)

之前学过,在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是可以实现多个接口的,这叫做接口的多实现。并且,一个类能继承一个父类,同时实现多个接口。

【修饰符】 class 实现类  implements 接口1,接口2,接口3。。。{
	// 重写接口中所有抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写
  	// 重写接口中默认方法【可选】
}

【修饰符】 class 实现类 extends 父类 implements 接口1,接口2,接口3。。。{
    // 重写接口中所有抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写
  	// 重写接口中默认方法【可选】
}

3、接口的多继承(extends)

一个接口能继承另一个或者多个接口,接口的继承也使用 extends 关键字,子接口继承父接口的方法。

4、接口与实现类对象构成多态引用

实现类实现接口,类似于子类继承父类,因此,接口类型的变量与实现类的对象之间,也可以构成多态引用。通过接口类型的变量调用方法,最终执行的是你new的实现类对象实现的方法体。

5、使用接口的静态成员

接口不能直接创建对象,但是可以通过接口名直接调用接口的静态方法和静态常量。

package com.atguigu.interfacetype;
​
public class TestUSB3 {
    public static void main(String[] args) {
        //通过“接口名.”调用接口的静态方法 (JDK8.0才能开始使用)
        USB3.show();
        //通过“接口名.”直接使用接口的静态常量
        System.out.println(USB3.MAX_SPEED);
    }
}

7.2.4jdk8中接口新特性

在JDK8.0 时,接口中允许声明默认方法静态方法

默认方法可以看为类中普通的方法

(3)公共的默认的方法:其中public 可以省略,建议保留,但是default不能省略

(4)公共的静态的方法:其中public 可以省略,建议保留,但是static不能省略

(1)类优先原则

当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的抽象方法重名,子类就近选择执行父类的成员方法。

2)接口冲突(左右为难)

  • 当一个类同时实现了多个父接口,而多个父接口中包含方法签名相同的默认方法时,怎么办呢?

选择保留其中一个,通过“接口名.super.方法名"的方法选择保留哪个接口的默认方法。

7.2.5抽象类和接口的对比

7.3内部类

7.3.1是什么,为什么?

将一个类A定义在另一个类B里面,里面的那个类A就称为`内部类(InnerClass)`,类B则称为`外部类(OuterClass)`。

具体来说,当一个事物A的内部,还有一个部分需要一个完整的结构B进行描述,而这个内部的完整的结构B又只为外部事物A
提供服务,不在其他地方单独使用,那么整个内部的完整结构B最好使用内部类。
 

比如:

Thread类内部声明了State类,表示线程的生命周期
HashMap类中声明了Node类,表示封装的key和value

7.3.2内部类的分类

 > 成员内部类:直接声明在外部类的里面。
        > 使用static修饰的:静态的成员内部类
        > 不使用static修饰的:非静态的成员内部类

 > 局部内部类:声明在方法内、构造器内、代码块内的内部类
        > 匿名的局部内部类
        > 非匿名的局部内部类

7.3.3成员内部类的理解

 > 从类的角度看:
        - 内部可以声明属性、方法、构造器、代码块、内部类等结构
        - 此内部类可以声明父类,可以实现接口
        - 可以使用final修饰
        - 可以使用abstract修饰

   > 从外部类的成员的角度看:
        - 在内部可以调用外部类的结构。比如:属性、方法等
        - 除了使用public、缺省权限修饰之外,还可以使用private、protected修饰
        - 可以使用static修饰

  1. 外部类访问成员内部类的成员,需要“内部类.成员”或“内部类对象.成员”的方式

  2. 成员内部类可以直接使用外部类的所有成员,包括私有的数据

  3. 当想要在外部类的静态成员部分使用内部类时,可以考虑内部类声明为静态的

实例化静态内部类
外部类名.静态内部类名 变量 = new 外部类名.静态内部类名();
变量.非静态方法()

实例化非静态内部类

外部类名 变量1 = new 外部类();
外部类名.非静态内部类名 变量2 = 变量1.new 非静态内部类名();
变量2.非静态方法();

7.3.4匿名局部内部类

new 父类([实参列表]){
    重写方法...
}
new 父接口(){
    重写方法...
}
interface A{
	void method();
}
public class Test{
    public static void test(A a){
    	a.method();
    }
    
    public static void main(String[] args){
    	test(new A(){

			@Override
			public void method() {
				System.out.println("aaaa");
			}
    	});
    }   
}

匿名内部类的对象作为实参

7.4枚举类

列出的实例系统会自动添加 public static final 修饰。

public enum SeasonEnum {
    SPRING("春天","春风又绿江南岸"),
    SUMMER("夏天","映日荷花别样红"),
    AUTUMN("秋天","秋水共长天一色"),
    WINTER("冬天","窗含西岭千秋雪");

    private final String seasonName;
    private final String seasonDesc;
    
    private SeasonEnum(String seasonName, String seasonDesc) {
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }
    public String getSeasonName() {
        return seasonName;
    }
    public String getSeasonDesc() {
        return seasonDesc;
    }
}

调用枚举类对象:SeansonEnum.SPRING

7.5包装类

7.5.1基本数据类型对应的包装类类型

byte -> Byte
short -> Short
int -> Integer
long -> Long
float -> Float
double ->Double

char -> Character
boolean -> Boolean
 

7.5.2自动装箱,自动拆箱

缓冲池:

自动装箱时优先调用缓冲池里的,如果是new出来的就在堆里

自动装箱:基本数据类型--->包装类

自动拆箱:包装类---->基本数据类型

基本数据类型---->包装类,valueOf

Integer i1 = Integer.valueOf(5);
Double d1 = Double.valueOf(2.2);

7.5.3String 与 基本数据类型、包装类之间的转换

String转换为基本数据类型

调用包装类的静态方法:parseXxx()

String s1 = "2";
int i = Integer.parseInt(s1);
String s2 = "false";
boolean b = Boolean.parseBoolean(s2);

基本数据类型转换为String

String.valueOf( xxx )

 
 String s = String.valueOf(2);

基本数据类型+""

7.5.4包装类API

Double.compare(double d1, double d2)
    
Integer.compare(int x, int y) 

7.6注解

7.6.1注解的理解

注解(Annotation)是从`JDK5.0`开始引入,以“`@注解名`”在代码中存在。
> Annotation 可以像修饰符一样被使用,可用于修饰包、类、构造器、方法、成员变量、参数、局部变量的声明。
  还可以添加一些参数值,这些信息被保存在 Annotation 的 “name=value” 对中。
> 注解可以在类编译、运行时进行加载,体现不同的功能。


7.6.2Java基础涉及到的三个常用注解

`@Override`: 限定重写父类方法,该注解只能用于方法
`@Deprecated`: 用于表示所修饰的元素(类,方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择
`@SuppressWarnings`: 抑制编译器警告

7.6.3元注解

元注解:对现有的注解进行解释说明的注解。
用在注解定义上面

(1)@Target:用于描述注解的使用范围
可以通过枚举类型ElementType的10个常量对象来指定
TYPE,METHOD,CONSTRUCTOR,PACKAGE.....

(2)@Retention:用于描述注解的生命周期
可以通过枚举类型RetentionPolicy的3个常量对象来指定
SOURCE(源代码)、CLASS(字节码)、RUNTIME(运行时)

唯有RUNTIME阶段才能被反射读取到。

(3)@Documented:表明这个注解应该被 javadoc工具记录。
(4)@Inherited:允许子类继承父类中的注解


7.6.4自定义注解

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
    String value();
}

7.7单元测试

在libraries中点击加号点击from Maven,输入org.junit.jupiter:junit-jupiter-engine:5.7.2

创建的类名不要为Test

八异常

8.1异常体系

java.lang.Throwable:异常体系的根父类
    |---java.lang.Error:错误。Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。
                         一般不编写针对性的代码进行处理。
               |---- StackOverflowError、OutOfMemoryError

    |---java.lang.Exception:异常。我们可以编写针对性的代码进行处理。
               |----编译时异常:(受检异常)在执行javac.exe命令时,出现的异常。
                    |----- ClassNotFoundException
                    |----- FileNotFoundException
                    |----- IOException
               |----运行时异常:(非受检异常)在执行java.exe命令时,出现的异常。
                    |---- ArrayIndexOutOfBoundsException
                    |---- NullPointerException
                    |---- ClassCastException
                    |---- NumberFormatException
                    |---- InputMismatchException
                    |---- ArithmeticException

我们处理的是编译时异常

8.2异常处理

8.2.1  try-catch-finally

try{
   ...... //可能产生异常的代码
}
catch( 异常类型1 e ){
   ...... //当产生异常类型1型异常时的处置措施
}
catch( 异常类型2 e ){
   ......     //当产生异常类型2型异常时的处置措施
}
finally{
   ...... //无论是否发生异常,都无条件执行的语句
}
 

> 如果声明了多个catch结构,不同的异常类型在不存在子父类关系的情况下,谁声明在上面,谁声明在下面都可以。
  如果多个异常类型满足子父类的关系,则必须将子类声明在父类结构的上面。否则,报错。
> catch中异常处理的方式:
   ① 自己编写输出的语句。
   ② printStackTrace():打印异常的详细信息。 (推荐)
   ③ getMessage():获取发生异常的原因。

> 更深刻的理解:无论try中或catch中是否存在仍未被处理的异常,无论try中或catch中是否存在return语句等,finally中声明的语句都一定要被执行。

8.2.2 throws


public void test() throws 异常类型1,异常类型2,.. {
    //可能存在编译时异常
}

如果父类被重写方法的方法签名后面没有 “throws 编译时异常类型”,那么重写方法时,方法签名后面也不能出现“throws 编译时异常类型”。

8.2.3  两种方式的选择

- 如果程序代码中,涉及到资源的调用(流、数据库连接、网络连接等),则必须考虑使用try-catch-finally来处理,保证不出现内存泄漏。
- 如果父类被重写的方法没有throws异常类型,则子类重写的方法中如果出现异常,只能考虑使用try-catch-finally进行处理,不能throws。
- 开发中,方法a中依次调用了方法b,c,d等方法,方法b,c,d之间是递进关系。此时,如果方法b,c,d中有异常,我们通常选择使用throws,而方法a中通常选择使用try-catch-finally。

8.3手动抛出异常  throw

throw new 异常类名(参数);

如果是编译时异常类型的对象,同样需要使用throws或者try...catch处理,否则编译不通过。

8.4自定义异常

(1)要继承一个异常类型

自定义一个编译时异常类型:自定义类继承java.lang.Exception

自定义一个运行时异常类型:自定义类继承java.lang.RuntimeException

(2)建议大家提供至少两个构造器,一个是无参构造,一个是(String message)构造器。

(3)自定义异常需要提供serialVersionUID

  1. 自定义的异常只能通过throw抛出。

  2. 自定义异常最重要的是异常类的名字和message属性。当异常出现时,可以根据名字判断异常类型。比如:TeamException("成员已满,无法添加");TeamException("该员工已是某团队成员");

  3. 自定义异常对象只能手动抛出。抛出后由try..catch处理,也可以甩锅throws给调用者处理。

class MyException extends Exception {
    static final long serialVersionUID = 23423423435L;
    private int idnumber;

    public MyException(String message, int id) {
        super(message);
        this.idnumber = id;
    }

    public int getId() {
        return idnumber;
    }
}

十常用类和api

10.1String类

10.1.1String类的声明

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence

> final:String是不可被继承的
> Serializable:可序列化的接口。凡是实现此接口的类的对象就可以通过网络或本地流进行数据的传输。
> Comparable:凡是实现此接口的类,其对象都可以比较大小。

10.1.2String类的属性

jdk8中:
private final char value[]; //存储字符串数据的容器
    > final : 指明此value数组一旦初始化,其地址就不可变。

jdk9开始:为了节省内存空间,做了优化
private final byte[] value; //存储字符串数据的容器。

10.1.3String实例化方式及构造器

第1种方式:String s1 = "hello";
第2种方式:String s2 = new String("hello");

String s2 = new String("hello");在内存中创建了几个对象? 两个!
一个是堆空间中new的对象。另一个是在字符串常量池中生成的字面量。

* `public String() ` :初始化新创建的 String对象,以使其表示空字符序列。
* `public String(String original)`: 初始化一个新创建的 `String` 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。
* `public String(char[] value) ` :通过当前参数中的字符数组来构造新的String。
* `public String(char[] value,int offset, int count) ` :通过字符数组的一部分来构造新的String。
* `public String(byte[] bytes) ` :通过使用平台的**默认字符集**解码当前参数中的字节数组来构造新的String。
* `public String(byte[] bytes,String charsetName) ` :通过使用指定的字符集解码当前参数中的字节数组来构造新的String。

10.1.4String连接,常量池

情况1:常量 + 常量: 结果仍然存储在字符串常量池中,返回此字面量的地址。注:此时的常量可能是字面量,也可能是final修饰的常量
情况2:常量 + 变量  或  变量 + 变量 :都会通过new的方式创建一个新的字符串,返回堆空间中此字符串对象的地址
情况3:调用字符串的intern():返回的是字符串常量池中字面量的地址

(了解)情况4:concat(xxx):不管是常量调用此方法,还是变量调用,同样不管参数是常量还是变量,总之,调用完concat()方法都返回一个新new的对象。

10.1.5String常用方法

10.2StringBuffer和StringBuilder

10.2.1StringBuffer和StringBuilder

> String:不可变的字符序列;底层使用char[] (jdk8及之前),底层使用byte[] (jdk9及之后)
> StringBuffer:可变的字符序列;JDK1.0声明,线程安全的,效率低;底层使用char[] (jdk8及之前),底层使用byte[] (jdk9及之后)
> StringBuilder:可变的字符序列;JDK5.0声明,线程不安全的,效率高;底层使用char[] (jdk8及之前),底层使用byte[] (jdk9及之后)

10.2.2源码分析

针对于StringBuilder来说:
内部的属性有:
    char[] value; //存储字符序列
    int count; //实际存储的字符的个数

不断的添加,一旦count要超过value.length时,就需要扩容:默认扩容为原有容量的2倍+2。
并将原有value数组中的元素复制到新的数组中。
 

10.2.3常用方法

增:
    append(xx)
删:
    delete(int start, int end)
    deleteCharAt(int index)
改:
    replace(int start, int end, String str)
    setCharAt(int index, char c)
查:
    charAt(int index)
插:
    insert(int index, xx)
长度:
    length()
 

10.2.4开发中的用法

> 如果开发中需要频繁的针对于字符串进行增、删、改等操作,建议使用StringBuffer或StringBuilder替换String.
  因为使用String效率低。
> 如果开发中,不涉及到线程安全问题,建议使用StringBuilder替换StringBuffer。因为使用StringBuilder效率高
> 如果开发中大体确定要操作的字符的个数,建议使用带int capacity参数的构造器。因为可以避免底层多次扩容操作,性能更高。
 

十一集合

十二泛型

十三IO流

13.1File类

File file = new File("d:\\atguigu\\javase\\HelloIO.java")

绝对路径

File file = new File("hello.txt")

相对路径,在单元测试test中,相对路径在当前module下,在main方法中,相对路径在projec下

一些常用方法,见课件

File类中只有新建、删除、获取路径等方法,不包含读写文件的方法。此时需要使用IO流

13.2IO流分类

四个抽象基类

Reader(字符读入),Writer(字符读出),InputSream(字节读入),OutputStream(字节读出)

13.3节点流(FileReader、FileWriter、FileInputSream、FileOutputStream)

节点流,直接作用在数据之上

涉及到流的关闭操作,异常应该使用try-catch-finall操作

13.3.1FileReader、FileWriter

new FileWriter(File file,false)或者new FileWriter(File file)默认为覆盖原文件,

new FileWriter(File file,true)为在原有文件后面添加内容

操作字符,用来处理文本文件

创建文件实例,创建流,具体读写操作,关闭流

1创建File实例      
File file = new File("dbcp_utf-8.txt");
File file1 = new File("dbcp_utf-8coopyy.txt");
2创建输入、输出流
FileReader fileReader = new FileReader(file);
FileWriter fileWriter = new FileWriter(file1);
3具体的读写操作
char[] chars = new char[5];
int len;
while ((len=fileReader.read(chars))!=-1){
    fileWriter.write(chars,0,len);
}

4关闭输入、输出流
fileWriter.close();
fileReader.close();

13.3.2FileInputSream、FileOutputStream

操作字节,处理音频,视频,图片等非文本文件

1创建File实例      
File file = new File("屏幕 2023-12-22 013034.png");
File file1 = new File("屏幕 2023-12-22 013034copy.png");
2创建输入、输出流
FileInputStream fileInputStream = new FileInputStream(file);
FileOutputStream fileOutputStream = new FileOutputStream(file1);
3具体的读写操作
byte[] bytes = new byte[1024];
int len;
while ((len=fileInputStream.read(bytes))!=-1){
    fileOutputStream.write(bytes,0,len);
}

4关闭输入、输出流
fileOutputStream.close();
fileInputStream.close();

13.4缓冲流

缓冲流要“套接”在相应的节点流之上,根据数据操作单位可以把缓冲流分为:

字节缓冲流BufferedInputStreamBufferedOutputStream

字符缓冲流BufferedReaderBufferedWriter

缓冲流的基本原理:在创建流对象时,内部会创建一个缓冲区数组(缺省使用8192个字节(8Kb)的缓冲区),通过缓冲区读写,减少系统IO次数,从而提高读写的效率。

输出流flush()方法

将缓冲区的数据写入到文件中

输出流关闭前flush()一下

String str = BufferedReader.readline();一次读一行

1创建file类对象
File file = new File("屏幕 2023-12-22 013034.png");
File file1 = new File("屏幕 2023-12-22 013034copycopy.png");

2创建输入输出流,缓冲流作用在节点流之上
FileInputStream fileInputStream = new FileInputStream(file);
FileOutputStream fileOutputStream = new FileOutputStream(file1;
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
3具体的读写操作
byte[] bytes = new byte[1024];
int len;
while ((len=bufferedInputStream.read(bytes))!=-1){
    bufferedOutputStream.write(bytes,0,len);
}
4关闭流,关闭最外面的流会自动关闭里面的流
bufferedOutputStream.close();
bufferedInputStream.close();

13.5转换流

13.5.1 InputStreamReader、OutputStreamWriter

InputStreamReader:将一个输入型的字节流转换为输入型的字符流。
OutputStreamWriter:将一个输出型的字符流转换为输出型的字节流。
 

将gbk文件复制一份,并保存为utf8格式,在idea中打开gbk格式的文件为乱码,默认为utf8格式
1创建File实例对象
File file = new File("dbcp_gbk.txt");
File file1 = new File("dbcp_utf8.txt");
2创建流
FileInputStream fileInputStream = new FileInputStream(file);
FileOutputStream fileOutputStream = new FileOutputStream(file1);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"gbk");//指定字符集,默认为utf8
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"utf8");
3具体的读写操作
char[] chars = new char[10];
int len;
while ((len=inputStreamReader.read(chars))!=-1){
    outputStreamWriter.write(chars,0,len);
}
4关闭流
inputStreamReader.close();
outputStreamWriter.close();

13.5.2字符集

在硬盘上:

ascii:主要用来存储a、b、c等英文字符和1、2、3、常用的标点符号。每个字符占用1个字节。

gbk:用来存储中文简体繁体、a、b、c等英文字符和1、2、3、常用的标点符号等字符。
    中文字符使用2个字节存储的。向下兼容ascii,意味着英文字符、1、2、3、标点符号仍使用1个字节。


utf-8:可以用来存储世界范围内主要的语言的所有的字符。使用1-4个不等的字节表示一个字符。
    中文字符使用3个字节存储的。向下兼容ascii,意味着英文字符、1、2、3、标点符号仍使用1个字节。

在内存中:

一个字符(char)占用2个字节。在内存中使用的字符集称为Unicode字符集。
 

13.6对象流

13.6.1ObjectOutputStream、ObjectInputStream*

ObjectOutputStream:将内存中的Java对象保存在文件中或通过网络传输出去

ObjectInputStream:将文件中的数据或网络传输过来的数据还原为内存中的Java对象
 

一些方法

oos.writeUTF("江山如此多娇,引无数英雄竞折腰");

Person p1 = new Person("Tom",12);
oos.writeObject(p1);


Person person = (Person) ois.readObject();

String str1 = ois.readUTF();

static修饰的,transient修饰的无法序列化

13.6.2 序列化与反序列化

序列化:使用ObjectOutputStream流实现。将内存中的Java对象保存在文件中或通过网络传输出去

反序列化:使用ObjectInputSteam流实现。将文件中的数据或网络传输过来的数据还原为内存中的Java对象

自定义类序列化要求:

① 自定义类需要实现接口:Serializable
② 要求自定义类声明一个全局常量: static final long serialVersionUID = 42234234L;
   用来唯一的标识当前的类。
③ 要求自定义类的各个属性也必须是可序列化的。
   > 对于基本数据类型的属性:默认就是可以序列化的
   > 对于引用数据类型的属性:要求实现Serializable接口

13.7标准输入输出流,打印流

十四网络编程

14.1InetAddress类

不对外提供构造器,创建实例的两种方法:

InetAddress localHost = InetAddress.getLocalHost();
InetAddress atguigu = InetAddress.getByName("www.atguigu.com");
InetAddress atguigu = InetAddress.getByName("192.163.0.1");
InetAddress inetAddress = InetAddress.getByName("www.atguigu.com");
System.out.println(inetAddress);
System.out.println(inetAddress.getHostAddress());获取ip地址
System.out.println(inetAddress.getHostName());获取主机名或域名

14.2Tcp协议

  • TCP协议进行通信的两个应用进程:客户端、服务端。

  • 使用TCP协议前,须先建立TCP连接,形成基于字节流的传输数据通道

  • 传输前,采用“三次握手”方式,点对点通信,是可靠的

    • TCP协议使用重发机制,当一个通信实体发送一个消息给另一个通信实体后,需要收到另一个通信实体确认信息,如果没有收到另一个通信实体确认信息,则会再次重复刚才发送的消息。

  • 在连接中可进行大数据量的传输

  • 传输完毕,需释放已建立的连接,效率低

  • @Test
        public void test15() throws Exception {
            File file = new File("屏幕 2023-12-22 013034.png");
            InetAddress inetAddress = InetAddress.getLocalHost();
            int port = 9000;
            Socket socket = new Socket(inetAddress,port);
    
            FileInputStream fileInputStream = new FileInputStream(file);
            OutputStream outputStream = socket.getOutputStream();
            byte[] bytes = new byte[1024];
            int len;
            while ((len = fileInputStream.read(bytes))!=-1){
                outputStream.write(bytes,0,len);
            }
            System.out.println("数据发送完成,客户端");
            客户端socket关闭输出流
            socket.shutdownOutput();
            InputStream inputStream = socket.getInputStream();
            ByteArrayOutputStream维护了一个byte数组,可以用来读取中文字符
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            byte[] bytes1 = new byte[5];
            int len1;
            while ((len1=inputStream.read(bytes1))!=-1){
                byteArrayOutputStream.write(bytes1,0,len1);
            }
            输出ByteArrayOutputStream
            System.out.println(byteArrayOutputStream.toString());
            byteArrayOutputStream.close();
            inputStream.close();
            outputStream.close();
            fileInputStream.close();
            socket.close();
        }

@Test
    public void test16() throws Exception {
        int port = 9000;
        ServerSocket serverSocket = new ServerSocket(port);
        客户端接受来自服务端的socket
        Socket accept = serverSocket.accept();
        File file = new File("屏幕 2023-12-22 013034客户端.png");
        InputStream inputStream = accept.getInputStream();
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        byte[] bytes = new byte[1024];
        int len;
        while ((len = inputStream.read(bytes))!=-1){
            fileOutputStream.write(bytes,0,len);
        }
        System.out.println("服务端,文件已接收");

        OutputStream outputStream = accept.getOutputStream();
        outputStream.write("客户端已成功接受".getBytes());
        outputStream.close();
        fileOutputStream.close();
        inputStream.close();
        accept.close();
        serverSocket.close();
    }

14.3Udp协议

发送端、接收端。

将数据、源、目的封装成数据包(传输的基本单位)Packet的实例不需要建立连接

  • 发送不管对方是否准备好,接收方收到也不确认,不能保证数据的完整性,故是不可靠的

  • 每个数据报的大小限制在64K

  • 发送数据结束时无需释放资源,开销小,通信效率高

  • 适用场景:音频、视频和普通数据的传输。例如视频会议

@Test
    public void sender() throws Exception {
        //1. 创建DatagramSocket的实例
        DatagramSocket ds = new DatagramSocket();

        //2. 将数据、目的地的ip,目的地的端口号都封装在DatagramPacket数据报中
        InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
        int port = 9090;
        byte[] bytes = "我是发送端".getBytes("utf-8");
        DatagramPacket packet =  new  DatagramPacket(bytes,0,bytes.length,inetAddress,port);
              
        //发送数据
        ds.send(packet);

        ds.close();
    }

    //接收端
    @Test
    public void receiver() throws IOException {
        //1. 创建DatagramSocket的实例
        int port = 9090;
        DatagramSocket ds = new DatagramSocket(port);

        //2. 创建数据报的对象,用于接收发送端发送过来的数据
        byte[] buffer = new byte[1024 * 64];数据包大小不超过64kB
        DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);

        //3. 接收数据
        ds.receive(packet);

        //4.获取数据,并打印到控制台上
        String str = new String(packet.getData(),0,packet.getLength());
        System.out.println(str);

        ds.close();
    }

14.4Url编程

URL的作用:定位互联网上某一资源的地址。

URL的格式

http://192.168.21.107:8080/examples/abcd.jpg?name=Tom   ---> "万事万物皆对象"
应用层协议 ip地址       端口号  资源地址   参数列表

/*
     * 需求:将URL代表的资源下载到本地
     * */
    @Test
    public void test1() {
        HttpURLConnection urlConnection = null;
        InputStream is = null;
        FileOutputStream fos = null;
        try {
            //1. 获取URL实例
            URL url = new URL("http://127.0.0.1:8080/examples/abcd.jpg");
            //2. 建立与服务器端的连接
            urlConnection = (HttpURLConnection) url.openConnection();
            //3. 获取输入流、创建输出流
            is = urlConnection.getInputStream();
            File file = new File("dest.jpg");
            fos = new FileOutputStream(file);
            //4. 读写数据
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
            System.out.println("文件下载完成");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //5. 关闭资源
            try {
                if (fos != null)
                    fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (is != null)
                    is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (urlConnection != null)
                urlConnection.disconnect();
        }


    }

十五反射

15.1Class类

获取Class实例的三种方式

//1.调用运行时类的静态属性:class
Class clazz1 = User.class;
System.out.println(clazz1);

//2. 调用运行时类的对象的getClass()
User u1 = new User();
Class clazz2 = u1.getClass();

//3. 调用Class的静态方法forName(String className)
String className = "com.atguigu02._class.User"; //全类名
Class clazz3 = Class.forName(className);

15.2类的加载器

15.2.1类的加载过程

5. 类的加载过程(了解)
过程1:类的装载(loading)
将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由类加载器完成

过程2:链接(linking)
> 验证(Verify):确保加载的类信息符合JVM规范,例如:以cafebabe开头,没有安全方面的问题。
> 准备(Prepare):正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配。
> 解析(Resolve):虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。

过程3:初始化(initialization)
执行类构造器<clinit>()方法的过程。
类构造器<clinit>()方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。


15.2.2类的加载器

> BootstrapClassLoader:引导类加载器、启动类加载器
     > 使用C/C++语言编写的,不能通过Java代码获取其实例

     > 负责加载Java的核心库(JAVA_HOME/jre/lib/rt.jar或sun.boot.class.path路径下的内容)

> 继承于ClassLoader的类加载器
    > ExtensionClassLoader:扩展类加载器
            > 负责加载从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录下加载类库
    > SystemClassLoader/ApplicationClassLoader:系统类加载器、应用程序类加载器
            > 我们自定义的类,默认使用的类的加载器。
    > 用户自定义类的加载器
            > 实现应用的隔离(同一个类在一个应用程序中可以加载多份);数据的加密。

15.2.3通过类的加载器来读取配置文件

配置文件,里面的key和value都为String类型,用来存放数据,实现数据和代码的分离

@Test
    public void method1() throws ClassNotFoundException, IOException {
        创建properties
        Properties properties = new Properties();
        通过ClassLoader.getSystemClassLoader()得到一个系统类加载器
        通过getResourceAsStream()获取一个输入流,路径为src下的文件
        InputStream resourceAsStream = ClassLoader.getSystemClassLoader().getResourceAsStream("info.properties");
        load()里面应该为一个输入流
        properties.load(resourceAsStream);
        
        读取配置文件
        String name = properties.getProperty("name");
        String age = properties.getProperty("age");
        System.out.println(name+":"+age);

    }

15.3反射获取运行时类的结构

调用指定的属性

调用指定的属性

获取Class实例
Class personClass = Person.class;
获取运行时类对象(jdk9之后不推荐使用,推荐使用调用构造)
Person person =(Person) personClass.newInstance();

getDeclaredField(String str)获取运行时类指定名的属性
Field name = personClass.getDeclaredField("name");
设置权限
name.setAccessible(true);
get(Object obj) (获取的操作)
或 set(Object obj,Object value) (设置的操作)进行操作
name.set(person,"cxk");
System.out.println(name.get(person));

获取类的属性
Field info = personClass.getDeclaredField("info");
info.setAccessible(true);
填具体对象的地方改为null
info.set(null,"蔡徐坤cln");
System.out.println(info.get(null));

调用指定的方法

Class personClass = Person.class;
Person person =(Person) personClass.newInstance();
Method show = personClass.getDeclaredMethod("show");
show.setAccessible(true);
通过方法名.invoke()来调用方法
show.invoke(person);

方法中含有形参,形参类型.class
Method showNation = personClass.getDeclaredMethod("showNation", String.class, int.class);
showNation.setAccessible(true);
invoke返回值类型默认为Object
String china = (String) showNation.invoke(person, "china", 18);
System.out.println(china);

调用指定的构造器,创建运行时类对象用此方法

Class personClass = Person.class;
空参构造器
Constructor declaredConstructor = personClass.getDeclaredConstructor();
调用newInstance()创建实例
Person person = (Person) declaredConstructor.newInstance();
System.out.println(person);

有参构造器
Constructor cxk = personClass.getDeclaredConstructor(String.class,int.class);
cxk.setAccessible(true);
Person person1 = (Person) cxk.newInstance("蔡徐坤",18);
ystem.out.println(person1);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值