Java语言编码规范:
1.大括号成对、对齐写
2.左大括号前有空格
3.代码缩进
4.方法和程序块之间空行
5.并排语句加空格
6.运算符两侧加空格
print()//输出不换行
println()//输出换行
输出换行:print(" ")或者print("/t")或者println()
注释:
单行注释://注释文字
多行注释:/*注释文字 */
文档注释(java.Doc):/** 注释文字 */
常量:
在程序执行过程中,其值不可以发生改变的量
分类:
字面值常量 | 自定义常量 |
---|---|
1.字符串常量(HelloWorld),2.整数常量(1),3.小数常量(1.2),4.字符常量(‘a’),5.布尔常量(true),6.空常量(null) | 了解 |
变量:
概念:
在程序执行的过程中,其值可以在某个方面内发生改变的量
本质:
内存中的一小块区域
格式:
数据类型 变量名 = 初始化值;
数据类型:变量变化的范围就是数据类型
变量名:每个变量都有一个名字,方便存取
初始化值:使用变量前,需要给变量赋值(或者通过系统输入,用Scanner类获取)
打印只需输出变量名即可,如果加双引号就输出的是字符串了
变量使用的注意事项:
1.变量未赋值,不能使用
2.变量只在它所属的范围内有效(作用域)
3.一行上可以定义多个变量,但是不建议这么写
数据类型及类型转化:
基本类型 | 引用类型 |
---|---|
整数型:byte(1个字节),short(2个字节),int(4个字节),long(8个字节);浮点数:float(4个字节),double(4个字节);字符型:char(2个字节);布尔型:boolean(1个字节) | 类:class;接口:interface;数组:[] |
注意:
定义long类型变量的时候,后面要+L(大小写都可,因为整型默认的是int),定义float类型变量的时候,后面要+F(大小写都可,浮点型默认的是double)
计算机存储数据的形式:
计算机中最小的存储单元是字节(Byte,用B表示),每个字节包括8个位(bit 用b表示)1TB = 1024GB
注意:
1.基本类型的变量作为参数传递时,传递的是值(相当于将值复制了一分,原来的值不发生变化)
2.引用类型的变量作为参数传递时,传递的是地址值
数据类型转化:
分类:
自动类型转化 | 强制类型转化 |
---|---|
小类型转化为大类型,运算结果为大类型 | 大类型转化为小类型,运算结果为小类型 |
格式:小类型 变量名 = (小类型)大类型数据
当大数据转化为小类型时,可能会造成精度缺失
标识符:
由英文大小写字母、数字、下划线(_)和美元符号($)组成
定义:
不能以数字开头,不能是关键字,严格区分大小写
命名规范:
类和接口 | 变量和方法 | 常量名 | 包名 |
---|---|---|---|
首字母大写,如果是多个单词,每个字母的首字母大写 | 首字母小写,如果有多个单词从第二个单词开始首字母大写 | 所有字母大写,出现多个字母用(_)隔开 | 遵循域名反写 |
运算符:
对常量和变量进行运算操作的符号
算数运算符 | 赋值运算符 | 关系运算符 | 逻辑运算符 | 三元运算符 |
---|---|---|---|---|
/ % + - ++ – | = += | == >= | && || ! | ? : |
表达式:
用运算符把常量和变量连接起来的式子
类型:
表达式的类型为表达式运算结果的数据类型
注意:
两个整数相除,结果还是整数;浮点数参与运算,结果还是浮点数
字符和字符串参与加法运算:
1.加号两边是数值型数据时,进行加法运算,‘a’ '0’等字符型数据参与运算时,用该字符在计算机中所表达的数值进行运算
2.加号两边有任意一边是字符串时,进行字符串的拼接
ASCII码表:
字符 | 0 | … | 9 |
---|---|---|---|
计算机中存储的值 | 48 | … | 57 |
字符 | a | … | z |
计算机中存储的值 | 97 | … | 122 |
字符 | A | … | Z |
计算机中存储的值 | 65 | … | 90 |
int a = 10;
char c = 'a';
System.out.println(a+c);
//就是a的值加上字符c对应的ASCII的值
System.out.println(10 + 20 + "hello");
//输出结果为30hello(前一个加号两边都是数值就直接进行相加,然后在跟后面加号进行字符串拼接)
自增和自减运算符:
++ | – |
---|---|
自增1 | 自减1 |
++在前,先自加在赋值,++在后先赋值在自加 | 同++ |
赋值运算符:
基本赋值运算符 | 扩展赋值运算符 |
---|---|
= | += -= /= *= %= |
关系运算符:
用来描述两个变量值之间的关系,关系运算符的结果都是布尔类型
逻辑运算符:
用于判断“并且”、“或者”、“除非”等逻辑关系,符号两端一般连接值为布尔类型的关系表达式。(&&;||;!)
&& | || | ! |
---|---|---|
两个都为真,则为真 | 其中一个为真则为真 | 取反 |
三元运算符:
格式:(关系表达式)?表达式1:表达式2;(关系表达式为true,结果为表达式1,否则为表达式2)
举例:int max = (a>b)?a:b;
Scanner类:
通过Scanner类扫描用户在控制台录入的数据
//第一步:导包(快捷键:alt+enter)
import java.util.Scanner;
public class ScannerDemo{
public static void main(String[] arges){}
//第二部:创建键盘录入对象
Scanner scanner = new Scanner(System.in);
//第三步:接收数据
int i = scanner.nextInt();//此处接受输入是为数字
System.out.println(i);
}
}
对于IO流的类一定要用完关闭,不然会一直占用内存(scanner。close())
流程控制结构:
顺序结构;选择结构;循环结构
//第一种格式:
if(关系表达式){
//语句体
}
//第二种格式:
if(关系表达式){
//语句体1
}else{
//语句体2
}
//第三种格式:
if(关系表达式1){
//语句体1
}else if(关系表达式2){
//语句体2
}//...
else{
//语句体n+1
}
switch:
//表达式取值类型:byte,short,int,char,JDK5后可以是枚举,JDK7后可以是String
switch(表达式){
case值1:
语句体1;
break;
case值2:
语句体2;
break;
...
default:
语句体n+1;
break;
}
循环结构:
for循环;while循环;do…while循环
for(初始化语句;判断条件语句;控制条件语句){
//循环体
}(快捷方式:限制条件+.+for)
获取多位数各个位上的数:个位:%10,十位:先/10再%10,以此类推
while(判断条件语句){
循环体语句;
控制条件语句;
}
do{
循环体语句;
控制条件语句;
}while(判断条件语句);
while和do…while的不同:while可能一次都循环不了,do…while至少循环一次
三种循环的区别:
1.格式不同
2.初始化语句不同
3.循环体的执行次数不同
4.使用场景不同
两种常见的死循环:
for( ; ;){
//循环体
}
while(true){
//循环体
}
循环常用关键字:
break | continue |
---|---|
中断,用在switch语句和循环语句,表示结束循环 | 继续,用于循环语句,表示结束本次循环,继续下次循环 |
带标号的循环:
即循环的名称,给循环定义一个标号
格式: 标号:for(){} break 标号 continue 标号
Random类:
//第一步:导包
import java.util.Random;
public class RandomDemo{
public static void main(String[]arges){
//第二步:创建Random类的对称
Random r = new Random();
for(int x = 1;x = 10;x++){
//第三步:获取随机数
int number = r.nextInt(10);
//获取的是0-9之间的随机数(10个)
System.out.println("number"+number);
}
}
}
方法:
完成特定功能的代码块
修饰符 返回值类型 方法名(参数类型 参数1,参数2...){
//方法体语句;
return 返回值;
}
方法调用:
1.通过方法名调用方法
2.传递实际参数
3.方法执行时,实际参数赋值给形式参数
4.在方法中进行运算,并将结果赋值给变量C
5.方法的返回值C赋值给接收者X
注意事项:
1.方法必须定义在类中
2.方法之间是平级关系,不能嵌套
3.方法没有返回值时,也要有返回值类型void(return省略)
4.return语句返回值类型必须和返回值类型匹配
5.return之后不能再放置语句
方法重载:
实现功能相同,但实现方式不同
在同一个类中,它们的方法名相同,参数列表不同称为方法重载,与返回值类型无关
参数列表不同:可以是参数个数不同,对应位置的参数类型不同
数组:
用来存储同一种数据类型多个元素的容器(可以是基本类型,也可以是引用类型)
数组的定义和访问:
数据类型[]数组名 = new 数据类型[长度](长度定义时指定,不可更改)
//方式1:
int[] arr = new int[3];
//方式2:
数据类型[]数组名 = new 数据类型 []{元素1,元素2...}
//方式3:
数据类型[]数组名 = {元素1,元素2...}
索引:
也叫下标,是数组元素距离数组起始位置的偏移量
arr[0]//数组第二个元素
直接输出数组名,得到的是数组的内存地址值
System.out.println(arr);//输出数组的内存地址
遍历数组:
for(int i = 0;i < arr.length;i++){
System.out.println(arr[i])
}
数组的初始化:‘
在内存中为数组开辟连续空间并为每个元素赋值的过程
动态初始化 | 静态初始化 |
---|---|
只指定长度,由系统给出默认值 | 给出初始化值,由系统决定数组长度 |
Java程序的内存分配:
方法区 | 栈 | 堆 |
---|---|---|
存储可运行的class文件,包含方法,静态成员,常量 | 方法运行时使用的内存(后进先出) | 存储new出来的数组或者对象 |
堆中new出来的对象生成地址然后栈中的变量指向该地址
数组arr存储的是数组在堆内存中的地址值,而不是数组元素的值,变量arr通过内存地址引用堆内存中的数组,所以数组是引用类型
面向对象:
三大特征:封装,继承,多态
类:
是一系列具有相同属性和行为的事物的统称(抽象概念)
对象:
是该类事物的具体体现,是一种具体存在
//创建一个对象 类名 对象名 = new 类名()
Animal Dog = new Animal();
//使用一个对象 对象名.变量名 对象名.方法名(...)
Dog.name;
Dog.call();
java中使用变量的规则:
就近原则:方法体里面有变量就使用方法体中的变量,没有就看成员变量中,如果有就使用,没有就报错
成员变量 | 局部变量 |
---|---|
类中,方法外 | 方法中或者形式参数 |
有默认初始化值 | 无默认初始化值,必须先赋值再使用 |
类中 | 方法中 |
堆中 | 栈中 |
随着对象的创建而存在,对象的消失而消失 | 随着方法的调用而存在,随着方法调用完毕而消失 |
局部变量和成员变量重名时,采用就近原则
封装:
封装的好处:1.提高安全性;2.提高复用性;3.将复杂的事情简单化
private关键字:
私有的,一种访问权限修饰符,用来修饰类的成员
特点:被修饰的成员只能在本类中访问
private 数据类型 变量名;
private 返回值类型 方法名(参数列表){}
this关键字:
特点:每一个普通方法都有一个this,谁调用该方法,this就指向谁
局部变量和成员变量重名时,用this关键字修饰成员变量即可
构造方法:
用来初始化对象,先通过new关键字创建对象,然后使用构造方法完成对象的初始化工作
快捷键:alt+insert或者右键选择构造方法,当要全选时ctrl+A即可
//格式:修饰符 构造方法名(参数列表){
//方法体
}
//要求:
//方法名必须与类名相同;没有返回值;没有返回值类型
public class Student{
public Student(){}//构造方法
}
//若未提供任何构造方法,系统会给出默认无参构造
//若已提供任何构造方法,系统不再提供无参构造
//构造方法可以重载
//空参创建对象
Student stu1 = new Student();
//有参创建对象
Student stu2 = new Student("张三",22);
一般父类中最好都写无参的构造方法和有参的构造方法
JavaBean类:
public class Student{
//成员变量
private String name;
private int age;
//无参构造
public Student(){}
//构造方法
public Student(String name, int age){
this.name = name;
this.age = age;
}
//设置姓名
public void setName(String name){
this.name = name;
}
//获取姓名
public void getName(){
return name;
}
//设置年龄
public void setAge(int age){
this.age = age;
}
//获取年龄
public void getAge(){
return age;
}
}
//构造方法初始化对象
Student stu1 = new Student("张三",22);
System.out.println(stu1.getName());//获取姓名
System.out.println(stu1.getAge());//获取年龄
继承:
使用场景:多个类中存在相同的属性和行为
让类与类之间产生父子关系,被继承的类叫做父类,继承的类叫做子类
//格式:
class 父类{
//...
}
class 子类 extends 父类{
//...
}
Java中,子类只能继承父类的非私有成员
继承的优缺点:
优点:
功能复用;便于扩展新功能;结构清晰,简化认识;易维护性
缺点:
打破了封装性;高耦合性
耦合:两个(或更多)模块相互依赖于对方
内聚:模块内部结构紧密,独立性强
程序追求的是:低耦合,高内聚
继承中变量的使用:
就近原则:先找局部变量,再找子类的成员变量,最后找父类的成员变量(成员方法一样)
//打印局部变量
System.out.println(price);
//打印子类成员变量
System.out.println(this.price);
//打印父类的成员变量
System.out.println(super.price);
对象初始化顺序:先初始化父类内容,再初始化子类内容
this和super的区别:
this | super |
---|---|
本质:对象;用法:从本类开始找 | 本质:父类内存空间的标识;用法:从父类开始找 |
理解:this就是new出来的整个对象,里面有若干内存地址,其中super是父类的内存空间的标识
构造方法的调用:
创建子类对象是先调用父类构造方法,因为子类的构造方法前默认有个super();访问了父类的空参构造,如果无默认无参构造,那就要手动调用父类的有参构造并赋值 super(“小黑”);
方法重写(Override):
定义:子类中出现和父类方法定义相同的方法的现象
解释:方法重写也叫方法的复写,覆盖,方法名、参数列表、返回值类型都要相同
注意事项:父类私有方法不能重写;子类方法访问权限不能小于父类方法;子类不能比父类抛出更大的异常
使用场景:扩展父类功能;父类功能过时,重新实现父类功能
四大权限修饰符:private;默认;protected;public
private:强调的是给自己使用
默认:强调的是给同包下的来使用
protected:强调的是给子类使用
public:强调的是给大家使用
方法重写和方法重载的区别:
重载 | 重写 |
---|---|
方法名:相同 | 方法名:相同 |
参数列表:不同(个数和对应位置) | 参数列表:相同 |
返回值类型:无关 | 返回值类型:相同 |
修饰符:无关 | 修饰符:访问权限不能小于被重写方法 |
定义位置:同一个类 | 定义位置:子父类中 |
继承特点:
只支持单继承,但支持多层继承;接口支持多继承
只能继承非私有成员
构造方法不能继承
只有子类符合父类的情况,才能继承
多态:
实现:抽象类和接口
同一对象在不同情况下表现出来的不同状态或行为
实现的步骤:1.要有继承关系;2.要有方法重写;3.父类引用指向子类对象
Animal an = new Dog();
多态中调用成员方法是编译看左(左边的类型有没有这个成员方法),运行看右(运行时具体执行的是右边的成员方法)
多态的使用场景:父类型作为形参的数据类型,这样就可以接受任意的子类对象
//Dog和Mouse继承父类Animal类
{
Dog d = new Dog();
d.setName("哈士奇");
showAnimal(d);
Mouse m = new Mouse();
m.setName("Jerry");
showAnimal(m);
}
public static void showAnimal(AAnimal an ){
an.eat();
}
//输出的是哈士奇吃骨头
// Jerry吃奶酪
多态中成员变量不可重写,遵循编译看左,运行看左的原则,
即在编译时会看左边的类型有没有这个成员变量,没有就报错,有就不报错,运行时使用的是左边的类型中的这个成员变量
public class Animal{
String name = "Animal";
}
public class Dog{
String name = "Dog";
}
public class Test{
psvm{
Animal an = new Dog();
Sout(an.name);
Dog d = new Dog();
Sout(d.name);
//输出结果为Animal和Dog
//编译看左,运行看左
}
}
好处 | 弊端 |
---|---|
可维护性;可扩展性 | 不能使用子类特有成员 |
当需要使用子类特有功能时,需要进行类型转化
向上转型(子类型转换成父类型) | 向下转型(父类型转换为子类型) |
---|---|
Animal animal = new Dog(); | Dog dog = (Dog)animal; |
注意:
1.只能在继承层次内进行转换
2.将父类对象转换成子类之前,使用instanceof进行检查
Animal an = new DOg();
Dog dog = (Dog)animal;
an.watch();//watch()是子类的特有方法
//输出狗看家
抽象类:
包含抽象方法的类,用abstract修饰
抽象方法:
只有方法声明,没有方法体的方法,用abstract修饰
当需要定义一个方法,却不明确方法的具体实现,可以将方法定义为abstract,具体实现延迟到子类,所以要求子类必须要重写(快捷:写eat然后点enter自动生成)
public abstract class Animal{
private String name;
public abstract void eat(){}//具体实现由子类去定义
}
抽象类的特点:
1.用abstract关键字修饰
2.修饰符 abstract class 类名{}
3.修饰符 abstract 返回类型 方法名{}
4.抽象类不能被实例化,只能创建子类对象
5.抽象类子类要么重写父类所有抽象方法,要么定义为抽象类
抽象类成员的特点:
成员变量:可以是普通的成员变量,也可以有成员常量(final)
成员方法:可以有普通方法,也可以有抽象方法,抽象类不一定有抽象方法,但有抽象方法的类一定是抽象类
构造方法:有构造方法,可以重载
final关键字:
用于修饰类、方法、变量;修饰的类不能被继承但可以继承其他类;修饰的方法不能被重写(不能和abstract共存);修饰的变量只能赋值一次,修饰引用类型的数据时,说明地址值不能改变,但可以修饰里面的数据
static关键字:
静态的;用于修饰类的变量;直接用类名.成员变量/成员方法名调用即可
被本类所有对象共享;在前面加上final可以防止修改(共有静态常量)
static修饰成员方法:
静态成员方法不能访问非静态成员
当用类名调用成员方法时即可将方法修饰成静态,用对象名调用时就设为普通方法
//交换数组中的值
for(int i = 0;i<arr.length/2[节省时间];i++){
int tmp = arr[i];
arr[i] = arr[arr.length-i-1];
arr[arr.length-1-i] = tmp;
}
接口:
用于描述类具有什么功能,但并不给出具体实现,类要遵循从接口描述的统一规则进行定义,接口是对外提供的一组规则、标准,简言之就是比抽象类还抽象的抽象类
//定义接口使用关键字interface
interface 接口名{}
//类和接口是实现关系
class 类名 implements 接口名
接口中的方法默认有public abstract修饰符
接口创建对象的特点:
接口不能实例化必须通过多态的方式实例化子类对象
接口的子类可以是抽象类,也可以是普通类,普通类必须重写方法
接口继承关系的特点:
接口与接口之间的关系是继承关系,可以多继承:接口 extends 接口1,接口2,接口3…
接口成员变量的特点:
接口中没有成员变量,只有公有的、静态的常量
public static final 常量名 = 常量值
接口成员方法的特点:
JDK7以前只有共有的、抽象方法:
public abstract 返回值类型 方法名();
JDK8以后可以有默认方法和静态方法:
public default 返回值类型 方法名(){}
static 返回值类型 方法名(){}
JDK9以后可以有私有方法:
private 返回值类型 方法名(){}
接口构造方法:
接口不能实例化,所以不用初始化
API:
指API文档,叫做“JAVA文档”,是JAVA中提供的类的使用说明书,就是学习JAVA中类的使用方法
JAVA中组件的层次结构:
模块(module)-- >包(package)–>类或者接口(class/interface)
模块:
自JAVA9起提供的一种新的JAVA基础组件,在包的基础上又进行了一层封装,是包的容器
JAVA语言:
JAVASE模块 | JDK模块 |
---|---|
包1;包2… | 包1;包2… |
类1;类2… | 类1;类2… |
JAVASE Modules:
JAVA语言的核心类库,其下的模块名多以Java开头
JDK Modules:
Java开发工具相关内容,其下的模块名多以jdk开头
Object类
类层次结构最顶层的基类,所有类都直接或间接的继承自Object类,所有的类都是Object的对象
java.base下的java.lang下的Object,java.lang包下的类不需要导包
成员方法:
int hashCode()
//返回对象的哈希码值,该方法通过对象的地址值进行计算,不同对象的返回值一般不同
Class<?> getClass()
//返回调用此方法对象的运行时类对象(调用者的字节码文件对象),一个类只有一个字节码文件
String toString()
//返回该对象的字符串表示,默认打印的是地址值,不同对象的地址值不同,地址值组成:全类名(包名+类名)+@+该对象的哈希码的无符号十六进制形式;输出语句直接打印对象,默认调用了该对象的toString()方法
boolean equals()
//返回其他某个对象是否与此对象“相等”。默认情况下比较两个对象的引用,建议重写
Scanner类:
用来获取键盘录入的数据,能够解析字符串和基本类型的数据
属于java.base下的java.util下的Scanner,需要导包
构造方法:
Scanner(InputStream):
//构造一个扫描器对象,从指定输入流中获取数据参数System.in,对应键盘录入
成员方法:
hasNextXxx():
//判断是否还有下一个输入项,其中Xxx可能是任意基本数据类型,返回结果为布尔类型
nextXxx():
//获取下一个输入项,其中Xxx可能是任意基本数据类型,返回对应类型的数据
String nextLine():
//获取下一行数据,以换行符作为分隔符
String next():
//获取下一个输入项,以空白字符作为分隔符;空白字符:空格、tab、回车
String类:
每一个字符串常量都是常量
属于java.base下的java.lang下的String
构造方法
String(byte[]):
//构造一个String对象,将指定字节数组中的数据转化成字符串
String(char[]):
//构造一个String对象,将指定字符数组中的数据转化成字符串
成员方法(判断)
boolean equals(String):
//判断当前字符串与给定字符串是否相同,区分大小写
boolean equalsIgnoreCase(String):
//判断当前字符串与给定字符串是否相同,不区分大小写
boolean startsWith(String):
//判断是否以给定字符串开头
String类的成员方法(获取)
int length():
//获取当前字符串的长度
char charAt(int index):
//获取指定索引位置的字符
int indexOf(String):
//获取指定字符(串)第一次出现的索引
int lastIndexOf(String):
//获取指定字符(串)最后一次出现的索引
String substring(int):
//获取指定索引位置(含)之后的字符串
String substring(int,int);
//获取从索引start位置(含)起至索引end位置(不含)的字符串
成员方法(转换)
byte[]getBytes():
//将字符串转化成字节数组
char[]toCharArray():
//将字符串转化成字符数组
static String valueOf(...):
String s3 = "" +123;
Sout(s3 + 4);//1234
//将指定类型数据转化成字符串
String replaced(old,new):
//将指定字符(串)替换成新的字符(串)
String[]split(String):
//切割字符串,返回切割后的字符串数据,原字符串不变
String trim():
//去掉字符串两端的空白字符
StringBuilder和StringBuffer类:
可变字符序列,用于构造字符串对象,里面有个长度可变的字符数组,使用的是相同的API
构造方法
StringBulider():
//构造一个空的StringBuilder容器
StringBuilder(String):
//构造一个StringBuilder容器,并添加指定字符串
成员方法
StringBuilder append(...):
//将任意数据添加到StringBuilder容器,返回自身
StringBuilder sb = new StringBuilder();
StringBuilder sb1 = sb.append("abc");
Sout(sb);
Sout(sb1);
//输出的都是abc,因为返回的是自身
String toString():
//将当前StringBuilder容器转换成字符串
Date和Calendar类:
属于java.base下的java.util下的Data/Calendar
日期和日历类,用于操作日期相关信息
构造方法
Data():
//构造一个日期对象,当前系统时间,精确到毫秒
Data(long):
//构造一个指定日期对象,时间为自“1970年1月1日00:00:00GMT”起,至指定参数的毫秒值
成员方法
long getTime():
//将日期对象转换成对应时间的毫秒值
static Calendar getInstance():
//根据当前系统时区和语言环境获取日历对象,java中的月份表示为0-11
int get(int field):
//返回给定日历字段的值
Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);//因为get()是静态方法,所以可以用类名直接调用
int month = c.get(Calendar.MONTH);//java中月份表示0-11
Sout(year+"年"+(month + 1)+"月")
void set(int field,int vaule):
//将给定的日历字段设置为指定的值(设置完以后还要重新获取调用get())
c.set(Calendar.YEAR 2021);//c.set(2000.10.26);
int year1 = c.get(Calendar.YEAR);
Sout(year1+"年")
基本类型的包装类:
基本数据类型不是对象,所以java针对基本类型提供了对应的包装类,以对象的形式来使用
装箱:基本类型转包装类型(对象类型);拆箱:包装类型(对象类型)转基本类型
成员方法
static 基本类型 parseXxx(String):
//将字符串类型的数据转换成对应的基本类型
String s = "10";
int num = Integer.parseInt(s);
//将字符串10转换成int类型的10
byte-->Byte
short-->Short
int-->Integer
long-->Long
char-->Character
float-->Float
double-->Double
boolean-->Boolean
//除了Character类以外,其他的7种包装类都有parseXXX()方法
Integer i1 = new Integer(20);
//装箱
int b = i1.intValue();
//拆箱
Sout(i1);
Sout(b);//都是20
Integer i2 = 30;//装箱
int c = i2//拆箱
集合:
能够描述出java集合框架的常用接口及各自特点
元素类型:引用类型(存储基本类型时自动装箱)
元素个数:不固定,可任意扩充
好处:不受容器大小限制,可以随时添加、删除元素,提供了大量操作元素的方法
都是接口,要用子类来实现
JAVA的集合体系:
单列集合(Collection) | 双列集合(Map) |
---|---|
List;Set | Map |
ArrayList;HashList(实现类) | HashMap(实现类) |
List集合:
特点:可重复、有序(存取顺序相同)
List list = new ArrayList();
//向集合中添加元素的方法为:add()
//获取集合中元素的方法为:get(索引)
//遍历集合的方式:for循环
//获取集合中元素个数的方法:size()
List list = new ArrayList();//util包下的要导包
Student s1 = new Student("张三",22);
Student S2 = new Student("李四",23);
Student s3 = new Student("王五",24);
Student S4 = new Student("老六",25);
list.add(s1);//在集合中添加s1
Object obj = list.get(2);//获取索引为2的元素
Sout(list.size());//获取集合的长度
for(int i = 0;i<list.size();i++){
Object obj2 = list.get(i);
Sout(obj2);
}//获取集合中的每个元素
增强for循环和迭代器(Iterator):
for(数据类型 变量名 : 数组或者集合对象){
//循环体,变量即元素
}
//快捷方式:iter+回车
//增强for的底层依赖的是迭代器,增强for就是迭代器的简写形式
迭代:对过程的重复;迭代器是遍历Collection集合的通用方式,可以在对集合遍历的同时进行添加、删除等操作
常用方法
next():返回迭代的下一个元素对象
hasNext():如果仍有元素可以迭代,就返回true
//通过迭代器遍历集合
List list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
Iterator it = list.iterator();//根据集合对象获取其对象的迭代器对象
while(it.hasNext()){
String s = (String)it.next();
Sout(s);
}
列表迭代器是List集合独有的遍历方式,可以在对集合遍历的同时进行添加、删除等操作,但是必须通过调用列表迭代器的方法来实现,所以普通的迭代器在遍历集合的时候不能进行添加和删除操作
用列表迭代器对集合遍历的同时进行添加和删除操作
list list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
ListIterator lit = list.listIterator();
while(lit.hasNext()){
String s = (String)lit.next();
if("b".equal(s)){//这样写可以避免空指针异常
lit.add("java");
}
}
泛型:
即泛指任意类型,又叫参数类型,对具体类型的使用起到辅助作用,类似于方法的参数
List <String> list = new ArrayList<>();
//好处:类型安全;避免了类型转换
泛型是jdk5的新特性,jdk7开始,后边的泛型不用写
Collection工具类:
sort(List<T>)//根据元素的自然顺序,将指定列表按升序排列
max(Collection<T>)//返回集合的最大元素
reverse(List<T>)//反转List集合元素
shuffle(List<T>)//使用默认的随机源随机置换指定的列表
都是静态方法,可直接用类名调用
List list = new ArrayList();
Collection.sort(list);
Set集合的特点和应用
特点:不可重复、无序;应用:Set set = new HashSet<>()
注意:因为Set集合保证元素的唯一性依赖:equals()和hashCode()两个方法,而Object类中equals()方法默认比较的是地址值是否相同,所以就出现了Set集合中相同的元素的情况
Map集合的特点和应用:
双列集合,元素由键值对(Entry)构成:key – value;注:key不可以重复,value可以重复
Map<T1,T2> map = new HashMap<>();
put()//向map集合中添加元素的方法;元素第一次添加返回null,重复添加返回旧值
keySet()//获取所有的key
get()//遍历keySet,通过key获取value
iterator()//遍历keySet
Map <Integer,Student> map = new HashMap<>();
Student s1 = new Student("张三",21);
Student s2 = new Student("李四",22);
Student s3 = new Student("王五",23);
map.put(1,s1);
Sout(map);//向集合中添加元素
Student s1 = map.get(2);//获取键值为2的元素
Sout(s1);
//遍历步骤:(思想:将双列集合的键值转换为单列集合,然后借助迭代器循环获取键值所对应的元素)
1.获取所有键的集合 keySet();
2.遍历所有的键,获取到每一个键 迭代器,增强for;
3.根据键值,获取指定的值 get();
Set<Integer> keys = key.keySet();
Iterator<Integer> it = key.iterator();//这里为什么要加泛型<Integer>:上面迭代的是键值是Interger类型的,下面是要通过键值来获取元素值,不加泛型默认是Object类型
遍历所有键:
法1:
while(it.hasNext()){
Iterator key = it.next();
Student value = key.get(key);
sout(value);
}
法2:
iter+回车{
Student value = map.get(key);
sout(value);
}
IO流:
输入输出,指的是数据像流体一样进行传输;在本地磁盘和网络上操作数据
IO流分类:
按数据流向分 | 按操作方式分 |
---|---|
输入流;输出流 | 字节流(InputStream;OutputStream);字符流(Reader;Writer) |
Reader:FileReader(普通的字符输入流);BufferedReader(高效的字符输入流)
Writer:FileWriter;BufferedWriter
InputStream:FileIputStream(普通的字节输入流);BufferedInputStream(高效的字节输入流)
OutputStrem:FileOutStrem;BufferedOutputStrem
异常:
非正常情况,通俗的说就是程序中出现的错误
异常(Throwable) | 错误(Error) |
---|---|
合理的应用程序可能需要捕获的问题 | 合理的应用程序不应该试图捕获的问题 |
NullpointException | StackOverFlowError |
异常的处理方式:
JVM默认的异常处理方式:在控制台打印错误信息,并终止程序
开发中异常的处理方式:
try…catch(finally):捕获,自己处理
throws:抛出,交给调用者处理
try{
//尝试执行的代码
}catch(Exception e){
//出现可能的异常之后的处理代码
}finally{
//一定会执行的代码,如关闭资源
}
//举例
try{
int a = 10/0;
sout(a);
}(Exception e){
sout("被除数不能为0");
}
sout("看看我执行了没有");
//结果是两句都被执行了,即使try...catch里面有return,finally里的语句依旧会被执行,不管有没有问题,finally里面的语句都会被执行
//throws:抛出,交给调用者处理
public void 方法名()throws Expection{
}//特点:执行结束后,程序不再继续执行
File类:
文件,文件夹,一个FIle对象代表磁盘上的某个文件或文件夹
构造方法:
File(String pathname)
File(String parent,String child)
File(File parent,String child)
成员方法:
createNewfile();//创建文件
mkdir()和mkdirs();//创建目录
//如果没有就创建返回true,如果有就不创建返回false
isDirectory();//判断File对象是否为目录
isFile();//判断File对象是否为文件
exists();//判断File对象是否存在
//举例:
使用时要导包
File file1 = new File("D:/abc/1.txt");//将D:/abc/1.txt封装成File对象;根据字符串形式的路径获取FIle对象
File file2 = new File("D:/abc/","1.txt")//根据字符串的父目录以及子目录来获取File对象
File file3 = new File("D:/abc/");//根据父目录对象,以及字符串形式的子目录来获取File对象
File file4 = new File(file3,"1.txt");
//在D盘下创建2.txt文件
File file5 = new File("D:/2.txt");
boolean flag = file5.createNewFile();
//第一次结果为true,第二次结果为flase
//在D盘下创建a文件
File file6 = new File("D:/a");
boolean flag2 = file5.mkdir();
//第一次结果为true,第二次结果为flase
//在D盘下创建a/b/c文件夹(多级目录)
File file7 = new File("D:/a/b/c");
boolean flag3 = file7.mkdirs();
//结果为true;mkdirs()既可以创建单级目录,也可以创建多级目录
//判断功能
File file8 = new File("D:/a/b/c");
boolean flag4 = file8.isDirectory();
boolean flag5 = file8.isFile();
boolean flag6 = file8.exists();
成员方法:
getAbsolutePath():获取绝对路径(以盘符开头的路径)
getPath():获取文件的相对路径(一般是相对于当前项目的路径来讲的)
getName():获取文件名
list():获取指定目录下所有文件(夹)名称数组
listFiles():获取指定目录下所有文件(夹)File数组
File file = new File("lib/1.txt");
file.getAbsolutePath();
file.getPath();
file.getName();//都用String类型做接收
File file1 = new File("lib");
String[]names = file1.list();
iter{
sout(name);//输出的只有父目录,看不到子目录
}
File[]files = file1.listFiles()
iter{
sout(file);//输出的是父类目录加上子类目录
}
字符流读写文件:
字符流读数据:
//一次读取一个字符
创建字符流文件对象:
Reader reader = new FileReader("readme.txt");
调用方法读取数据
int data = reader.read();
//读取一个字符,返回该字符代表的整数,若达到流的末尾,返回-1
异常处理:
throws IOException
关闭资源:
reader.close();
Reader reader = new FileReader("lib/1.txt");
int ch;
while((ch = reader.read()) != -1){
ch = reader.read();
sout(ch);
}
reader.close();
//一次读取一个字符数组
创建字符流读取文件对象
Reader reader = new FileReader("reaadme.1.txt");
调用方法读取数据
char[]chs = new char[2048];
int len = r.read(chs);
//读取字符到数组中,返回读取的字符数,若达到流的末端,返回-1
异常处理:
throws IOException
关闭资源:
reader.close();
Reader reader = new FileReader("lib/2.txt");
char[] chs = new char[3];
int len1 = reader.read(chs);//Reader类中的方法 int read(char[] chs:一次读一个字符数组,将读取到的内容存入到数组中,并返回读取到的有效字符数,读不到返回-1)
sout(chs);
sout(len1);
Reader reader = new FileReader("lib/2.txt");
char[] chs = new char[3];
int len;
while((len = reader.read(chs)) != -1){
String s = new String(chs,0,len);//chs:表示要操作的数组;0:表示索引的起始地址;len:表示要操作的字符个数
sout(s);
}
字符流写数据
按单个字符写入
//创建字符流写对象
Writer writer = new FileWriter("dest.txt");
//创建方法写入数据
int x = '中';//字符根本是整数
writer.write(x);//写一个字符
char[] chs = {'橙','心','橙','意'}
writer.write(chs);//写一个字符数组;writer.write(chs,0,2):写入起始索引为0,长度为2的字符数组chs
writer.write("小黑爱学习");//写一个字符串
//写入时如果文件中已有数据,就用写入的覆盖原有的
//异常处理
throws IOexception
关闭资源:
writer.close();
字符流拷贝文件(只能拷贝纯文本文件):
按单个字符读写
创建字符流读文件对象:
Reader reader = new FileReader("readme.txt");
创建字符流写入文件对象:
Writer writer = new FileWriter("dest.txt");//如果目标文件不存在,系统会自动创建
调用方法读取文件:
int data = reader.read();
调用方法写入数据:
writer.write(data);
异常处理:
throws IOException
关闭资源:
reader.close();
writer.close();
按字符数组读写
FileReader fr = new FileReader("readme.txt");
FileWriter fw = new FileWriter("dest.txt");
char[] chs = new char[len];
int len = fr.read(chs);//读入数组中的字符并返回字符长度
fw.write(chs,0,len);
fr.close();
fw.close();
字符缓冲流拷贝文件的标准代码:
BufferedReader类中的方法
//构造方法
BufferedReader(Reader reader);
//成员方法
public String readLine()//一次读取一行数据并返回读取到的内容,读不到返回null
BufferedWriter类中的方法
public void newLine()//根据当前操作系统给出对应的换行符
BufferedReader/BufferedWriter
创建字符缓冲流读文件对象:
BufferedReader br = new BufferedReader(new FileReader("readme.txt"));
创建字符流写文件对象
BufferedWriter bw = new BufferedWriter(new FileWriter("dest.txt"));
异常处理
throws IOException
使用while循环读写数据
int len;
while((len = br.read()) != -1){
bw.write(len);
}
关闭资源
br.close();
bw.close();
//字符缓冲流一次读写一行的方式拷贝文件
BufferedReader br = new BufferedReader(FileReader(lib/1.txt));
BufferedWriter bw = new BufferedWriter(FileWriter("lib/2.txt"));
String str;
while((str = br.readLine()) != null){
bw.write(str);
bw.write("\r\n");//直接写bw.newLine();即可不用担心换行符
}
br.close();
bw.close();
字节流读写文件:
字节流拷贝文件:
FileInputStream类中的方法
//构造方法
public FileInputStream(String pathname);
//成员方法
public int read();//一次读取一个字节,并返回读取到内容,读不到就返回-1
FileOutStream类中的方法
public FileOutStream(String pathname);
//构造方法
public void write(int len)//一次写入一个字节
//按单个字节读写
创建字节流读文件对象:
InputStream is = new FileInputStream("Desktop.jpg");
创建字节流写文件对象:
OutputStream os = new FileOutStream("D:/桌面.jpg");
异常处理:
throws IOException
使用while循环读写数据:
int b;
while((b = is.read()) != -1){
os.write(b);
}
is.close();
os.close();
//按字节数组读写
FileInputStream fis = new FileInputStream("Desktop.jpg");
FileOutputStream fos = new FileOutputStream("D:/桌面.jpg");
byte[] b= new byte[2048];
int len;
while((len = fis.read(b)) != -1){
fos.write(b,0,len);
}
fis.close();
fos.close();
字节缓冲流拷贝文件的标准代码:
//创建字符缓冲流拷贝文件对象:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.jpg"));
//创建字节缓冲流写文件对象:
BufferedOutputStream bos = new BufferedOutPutStream(new FileOutputStream("b.jpg"));
//异常处理:
throws IOException
//使用while循环读写数据:
int len;
while((len = bis.read()) != -1){
bos.write(len);
}
bis.close();
bos.close();
总结:拷贝纯文本文件用字符流,拷贝其他(图片,音频,视频)用字节流
//模拟用户上传头像
package Demo4;
import java.io.*;
import java.util.Scanner;
public class shangchuantouxiang {
public static void main(String[] args) throws IOException {
//需求:模拟用户上传头像的功能,假设所有的用户头像都上传到项目lib文件夹中
//1.定义一个方法,用来获取要上传的用户头像的路径 getPath()
File file = getPath();
//2.定义一个方法,用来判断要上传的用户头像在lib中是否存在;用getName()获取路径最后的文件名
boolean flag = isExists(file.getName());
//3.如果存在,提示:该用户头像已经存在,上传失败
if(flag){
System.out.println("该用户头像已经存在,上传失败");
}
//4.如果不存在,就上传该用户头像,并且提示上传成功,定义一个方法用于上传具体的用户头像
else{ uploadFile(file);
}
}
public static File getPath(){
//1.提示用户录入要上传的头像,并接受
Scanner sc = new Scanner(System.in);
String path = sc.nextLine();
//7.因为不知道用户多少次能录入正确,所以用while(true)改进
while(true){
System.out.println("请录入您要上传的用户头像的路径:");
//2.判断该路径的后面是否是:jpg,png,bmp
//3.如果不是提示:您录入的不是图片,请重新录入
if(!path.endsWith(".jpg") && !path.endsWith(".png") && !path.endsWith(".bmp")){
System.out.println("您录入的不是图片,请重新录入");
continue;
}
//4.如果是,将其封装成对象,判断该路径是否存在,并且是否是文件
File file = new File(path);
if(file.exists() && file.isFile()){
//6.如果是,直接返回
return file;
} else {
//5.如果不是,提示:您录入的路径不合法,请重新录入
System.out.println("您录入的路径不对,请重新录入");
}
}
}
public static boolean isExists(String path){
//1.将lib下的文件夹封装成File对象
File file = new File("lib");
//2.获取lib文件夹中所有的文件的名称数组
String [] names = file.list();
//3.遍历数组,与获取到的数据依次进行比较
for (String name : names) {
if(name.equals(path)){
//4.如果是就说明该用户头像已经存在,返回true
return true;
}
}
//5.如果不一致,说明该用户头像不存在,返回false
return false;
}
public static void uploadFile(File path) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("lib/"+path.getName()));
int len;
while((len = bis.read()) != -1){
bos.write(len);
}
bis.close();
bos.close();
System.out.println("上传成功");
}
}
反射:
在程序运行过程中分析类的一种能力
作用:
1.分析类:
加载并初始化一个类
查看类的所有属性和方法
2.查看并使用对象
查看一个对象的所有属性和方法
使用对象的任意属性和方法
反射的应用场景:
构建通用的工具
搭建具有高度灵活性和扩展性的系统框架
分析:
编写java程序先在.java的源文件中编写代码,然后编译成.class文件,然后用对象的形式调用方法,而反射就是先用对象调用方法,然后获取.class文件,之后就可以使用.java里的构造方法,成员方法和属性
类加载器(ClassLoader):
负责将类的字节码文件(.class文件)加载到内存中,并生成对应的Class对象
Class对象:
java.lang.Class类的对象,也叫字节码文件对象,每个Class对象对应一个字节码文件
类的加载时机(什么时候使用类加载器):
1.创建类的实例
Student stu = new Student();
2.访问类的静态成员
Calendar.getInstance();
3.初始化类的子类
class User extends Person{}
User user = new User();//先加载父类
4.反射方式创建类的Class对象
Class class = Class.forName(“类的正名”);
正名:包名+类名(例:cn.itcast.demo.Student)
//获取Class对象的三种方法
//1.Object类的getClass()方法
Class clazz = 对象名.getClass();
//2.类的静态属性
Class clazz = 类名.class;
//3.Class类的静态方法
Class clazz = Class.forName("类的正名")
//创建Student类属于包cn.itcast.demo1
Student stu = new Student();
//方式一:
Class clazz = stu.getClass();
//方式二:
Class clazz2 = Student.class;
//方式三:
Class class3 = class.forName("cn.itcast.demo1.Student")//快捷方式:右键Student类选择copy reference然后粘贴
//判断Class对象是否是同一个对象,只需sout(clazz = clazz1)//如果为true则表明一个字节码文件对应一个Calss对象
//反射方式获取构造方法并使用(先通过Class对象获取构造器对象,再由构造器对象获取构造方法)
Constructor<T>对象
//构造器对象,属于java.base模块,java.lang.reflect包
通过Class对象获取构造器对象
getConstructor(Class<?>...parameterTypes)
//返回一个Constructor对象,仅公共构造函数
...:可变参数,代表Calss类型的数组,可以传一个Class对象,也可以不传
?:通配符,代表不确定的任意类型
getDeclaredConstructor(Class<?>...parameterTypes)//传入的是字节码文件
//返回一个Constructor对象,可获取私有构造函数
getConstructors()
//返回此类所有(不含私有)构造函数的数组
Constructor的常用方法
String getName()
//返回构造函数名
T newInstance(Object...initargs)
//使用此构造函数和指定参数创建并初始化对象
public class Student{
public Student(){}
public Student(String name){
sout("您录入的name的值是:"+name);
}
public Student(int age){
sout("您录入的age的值是:"+ age);
}
}
//通过反射的方式创建Student类型的对象
//1.获取Student类的字节码文件对象
Class clazz = class.forName("cn.itcast.demo1.Student");
//2.根据第一步获取到的字节码文件对象,获取指定的构造器对象
//2.1获取公共的无参构造
Constructor con1 = clazz.getConstructor();
//2.2获取公共的有参构造
Constructor con2 = clazz.getConstructor(String.class);
//2.3获取私有的有参构造
Constructor con3 = clazz.getDeclaredConstructor(int.class);
//2.4获取Student类的所有公共的构造函数
Constructor[] cons = clazz.getConstructors();
iter+回车遍历数组打印输出
//获取构造器的名字,看看他是哪个类的构造
String name = con.getName();
sout(name);
//获取构造器对象和参数,创建对应的Student对象
Student stu = (Student)con.newInstance("张三");//创建的是Object型的对象,所以要向下转型
//通过反射方式获取成员方法并使用
Method对象
方法对象,属于java.base模块,java.lang.reflect包
//通过Class对象获取方法
getMethod(String name,Class<?>...parameterTypes)
//返回一个Method对象,仅公共成员方法‘
name:方法名
parameterTypes:方法的参数列表
getDeclaredMethod(String,Class<?>...)
//返回一个Method对象,可获取私有成员方法
getMethods()
//返回此类所有方法的数组(不含私有)
Method的常用方法
String getName()
//返回方法名
Object invoke(Object obj,Object...args)
//在指定对象上调用此方法,参数为args
//通过反射的方法获取Student类中的成员方法并调用
public class Student(){
public void show1(){
sout("我是公共的空参方法");
}
public void show2(int a){
sout("我是公共的带参方法,传入a的值是:"+ a);
}
private int show3(int a,int b){
sout("我是私有方法");
return a + b;
}
}
//1.获取Student类的字节码文件对象
Class clazz = Class.foeName("cn.itcast.demo3.Student");
//2.获取该类的构造器对象,然后创建Student类的对象
Constructor con = clazz.getConstructor();
Student stu = (Student)con.newInstance();
//3.获取该类成员方法对象,然后调用此方法
//调用公共的空参方法
Method method1 = clazz.getMethod("show1");//打印方法对象
sout(method1.getName());//打印方法名
method1.invoke(stu);//调用方法
//调用公共的带参方法
Method method2 = clazz.getMethod("show2",int.class);
method2.invoke(stu,100);
//调用私有的带参方法
Method method3 = clazz.getDeclaredMethod("show3",int.class,int.class);
//成员方法是私有的那么就要在调用方法前开启暴力反射 public setAccessible(boolean flag)
method3.setAccessible(true);
int sum = (int)method3.invoke(stu,10,20);
//获取Student类中的所有成员方法
Method[]methods = class.getMethods();
iter+回车遍历数组
//通过反射获取类的Setter方法,并创建该类的对象
//通过反射获取Student类的构造方法,并创建该类的对象
Constructor con = clazz.forName("cn.itcast.demo1.Student");
Student stu = (Student)con.newINstance();
//获取到指定的getName(),给Student对象设置值
Method method1 = clazz.getMethod("setName",String.class);
method1.invoke(stu,"张三");
//反射方式获取成员变量并使用
File对象
域(属性、成员变量)对象,属于java.base模块,java.lang.reflect包
//通过Class对象获取属性
getField(String name)
//返回一个Field对象,仅公共属性;name:属性名
getDeclaredField(String name)
//返回一个Field对象,可以获取私有属性
getDeclaredFields()
//返回此类所有(含私有)属性的数组
Field的常用方法
void set(Object obj,Object value)
//设置obj对象的指定属性值为value
void setAccessible(boolean flag)
//将此属性的可访问行设置为指定布尔类型
//通过反射获取成员变量并使用
//1.获取Student类的字节码文件对象
Class clazz = clazz.forName("cn.itcast.demo1.Student");
Constructor con = clazz.getConstructor();
Student stu = (Student)con.newInstance();
Field field1 = clazz.getField("name");
field1.set(stu,"张三");
field1.setAccessible(true);
field1.set(stu,30);
总结:类加载器对象和Method对象默认的是Object类,所以在创建其对象的时候要使用向下转型;当成员方法和成员变量的属性是私有的时候在调用并使用的时候要开启暴力反射
注解(Annotation,也叫元数据):
JDK1.5及以后版本引入的一个特性,可以声明在包、类、字段、方法、局部变量、方法参数等前面,用来对这些元素进行说明,注释
使用:@注解名称
作用:
1.编写文档:通过代码里标识的注解生成文档(生成文档doc文档)
2.代码分析:通过代码里标识的注解对代码进行分析(使用反射)
3.编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查(Override:如果子类没有重写父类中指定的方法,编译器就会报错)
JDK中预定的一些注解:
@Override:检测被该注解标注的方法是否继承父类
@Deprecated:该注解标注的内容,表示已过时
@SuppressWarnings:压制警告@SupperWarnings("all");//写在类上面,压制所有的警告
自定义注解:
本质:本质上就是一个接口,该接口默认继承Annotation接口
格式:
元注解:用于描述注解的注解
@Target:描述注解能够作用的位置
ElementType取值:
TYPE:作用于类上
METHOD:作用于方法上
FIELD:作用于成员变量
@Retention:描述注解被保留的阶段
@Retention(retentionPolicy.RUNTIME):当前被描述的注解会被保留到class字节码文件中,并被JVM读取到
@Documented:描述注解是否被抽取到API文档中
@Inherited:描述注解是否被子类继承
@Target(value = {ElementType.TYPE})//表示该注解只能作用在类上
public @interface Myanno3{}
public @interface MyAnn0(注解名称){
int age();
String name() default "张三";//调用注解时不用赋值,默认是张三
MyAnno2 anno2();
String[] strs();
}
属性:接口中可以定义的成员方法
要求:
1.属性的返回值类型
基本数据类型;String;枚举;注解;以上类型的数组
2.定义了属性,在使用时需要给属性赋值
如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值
如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可
数组赋值时,值使用{}包裹,如果数组中只有一个值{}省略
@MyAnno(age = 21,anno2 = @MyAnno2,strs = {"abc","def"})//给注解赋值初始化
解析注解:
//获取注解中定义的属性值
1.获取注解定义的位置的对象
2.获取指定的注解(getAnnotation(class))
3.调用注解中的抽象方法获取配置值
//定义的注解
@Target({ElementType.TYPE})
@Retention(RetentionPOlicy.RUNTIME)
public @interface Pro{
String className();
String methodName();
}
package cn.itcast.annotation;
public class Demo1{
public void show(){
sout("demo1...show...");
}
}
package cn.itcast.annotation;
public class Demo2{
public void show(){
sout("demo2...show...");
}
}
@Pro(className = "cn.itcast.annotation.DEmo1",methodName = "show")
public class ReflectTest{
public static void main(String[] args)throws Exception{
//1.解析注解
//1.1获取该类的字节码文件对象
Class<ReflectTest> reflectTestClass = ReflectTest.class//类名获取字节码文件对象
//2.获取上边的注解对象//字节码文件对象获取注解对象getAnnotation(class对象)
Pro an = reflectTestClass.getAnnotation(Pro.class);//其实就是在内存中生成了一个该注解对象的子类实现对象
// public class ProImpl implements Pro{
// public String className(){
// return"cn.itcast.annotation.Demo1";
// }
// public String methodName(){
// return"show";
//}
//}
//3.调用注解对象中定义的抽象方法,获取返回值
String className = an.className();
String methodName = an.methodName();
Class cls = Class.forName(className);
Object obj = cls.newIntance();
Method method = cls.getMethod(methodName);
method.invoke(obj);
}
}
{ElementType.TYPE})//表示该注解只能作用在类上
public @interface Myanno3{}
public @interface MyAnn0(注解名称){
int age();
String name() default “张三”;//调用注解时不用赋值,默认是张三
MyAnno2 anno2();
String[] strs();
}
属性:接口中可以定义的成员方法
要求:
1.属性的返回值类型
基本数据类型;String;枚举;注解;以上类型的数组
2.定义了属性,在使用时需要给属性赋值
如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值
如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可
数组赋值时,值使用{}包裹,如果数组中只有一个值{}省略
@MyAnno(age = 21,anno2 = @MyAnno2,strs = {“abc”,“def”})//给注解赋值初始化
##### 解析注解:
```java
//获取注解中定义的属性值
1.获取注解定义的位置的对象
2.获取指定的注解(getAnnotation(class))
3.调用注解中的抽象方法获取配置值
//定义的注解
@Target({ElementType.TYPE})
@Retention(RetentionPOlicy.RUNTIME)
public @interface Pro{
String className();
String methodName();
}
package cn.itcast.annotation;
public class Demo1{
public void show(){
sout("demo1...show...");
}
}
package cn.itcast.annotation;
public class Demo2{
public void show(){
sout("demo2...show...");
}
}
@Pro(className = "cn.itcast.annotation.DEmo1",methodName = "show")
public class ReflectTest{
public static void main(String[] args)throws Exception{
//1.解析注解
//1.1获取该类的字节码文件对象
Class<ReflectTest> reflectTestClass = ReflectTest.class//类名获取字节码文件对象
//2.获取上边的注解对象//字节码文件对象获取注解对象getAnnotation(class对象)
Pro an = reflectTestClass.getAnnotation(Pro.class);//其实就是在内存中生成了一个该注解对象的子类实现对象
// public class ProImpl implements Pro{
// public String className(){
// return"cn.itcast.annotation.Demo1";
// }
// public String methodName(){
// return"show";
//}
//}
//3.调用注解对象中定义的抽象方法,获取返回值
String className = an.className();
String methodName = an.methodName();
Class cls = Class.forName(className);
Object obj = cls.newIntance();
Method method = cls.getMethod(methodName);
method.invoke(obj);
}
}