一、基础部分
注释
文档注释: javadoc
/**
*@author
*@version
*@since 需要最早使用的jdk版本
*@param 参数
*@return
*@throws
*/
命令行实现,路径+Javadoc -encoding UTF-8 -charet -UTF8
数据类型
byte | short | int | long | float | double | boolean | char | |
---|---|---|---|---|---|---|---|---|
所占字节 | 1 | 2 | 4 | 8 | 4 | 8 | 1 | 2 |
byte -->double 也是类型由低到高的排序
拓展:
1、long类型要在数字后面加 L ,long num1=10L;
2、float类型在后面加个f , float num2=10.1F;
3、bit是8位的二进制数
4、Byte(字节) 1B = 8 bit(位)
5、float 有限, 离散 ,舍入误差 , 大约 ,接近而不等于 --> 最好避免使用进行比较
(可用 BigDecimal 类)
6、 关于字符, 编码Unicode表 范围:U000~UFFF
例: char c =’ \u 0061’ --> c=A
\u是转义字符,0061是A的Unicode编码
类型转换
注意问题:
一、 操作数比较大时,注意溢出问题或精度问题
int num1 = 10_000_000; jdk7 特性,数字间可以用下划线分割且不会输出下划线
int num2 =20;
int total = num1 *num2; 计算时溢出了
–> int转换long:long total= num1 * num2; 计算前默认是 int
解决方法:long total =num1 * ( ( long) num2 );
num1 和 num2 位置可互换没有优先级
二、
1、强制转换 高–> 低
2、自动转换 低–>高
3、不能转换布尔型
运算符
一、自增/减:
int a=3;
int b = a++ —>执行完代码后,a才自加
a = 4 ,b = 3
int c= ++a —>a先自加然后执行代码
a = c =5 //注意同一个程序中a的值的变化
二、幂运算(Math类的使用)
double p =Math.pow(3,2);
三、逻辑运算
短路运算:
以逻辑与为例:两个变量都为真,result为真
b&&a,从左到右运算,上来就发现b是假,代码就没有继续执行的必要了,返回假
int a =5;
boolean b = (c<4)&&(c++ <4);
println(a); -----> a=5,没有变为6是因为c<4为假,程序停止,后面的c++ <4没有执行
println(b); -----> false
四、位运算
/**
A=0011 1100
B=0000 1101
- &与, 0000 1100 两个1为1,其余为0
- |或, 0011 1101 有一个1即为1,其余为0
- ^异或, 0011 0010 相同为0,不同为1
- ~取反
*/
左/右移:
<< 左移,移动1位相当于*2,>>右移,移动一位相当于/2
例:2 * 8 = 2 * 2 *2 *2 ,通过二进制运算,计算机运算效率更高
0000 0010 ,2
0000 1000 ,8
0001 0000,16
2<<3 —>移动3位,得到16
Scanner
// if(scanner.hasnext())—>判断是否有输入
一、next()
1、对于输入有效字符前遇到的空白,next()会自动去除
2、输入有效字符后,空白会作为结束符
3、next()得不到带有空格的字符
二、nextline()
1、以回车为结束符
2、可以获得空白
标签
goto 在Java中不能使用,但却有其缩影。
与break和continue联合使用的标签
例:label: for(i=0;i<5;i++){
for(j=0;j<i;j++)
{
if(){};
break /continue lable;
}
}
变量
1、局部变量
作用域一般在相应的方法区
2、实例变量
从属于类,作用域一般在类里面方法外面
Class A{
int age; //实例变量/类变量
main{
A a = new A();
a.age=1;
}
public void method(int i){
};
3、类变量
static修饰,在一个类中可以直接调用
作用域在一个源文件
补充:修饰符不存在先后顺序
命令行传参
public static void main (string args[] )
{
system.out.println(args[0]);
system.out.println(args[1]);
//实际上就是一个数组
}
主方法也是可以传递参数的
在cmd中找到文件所在的第一目录,输入路径运行该Java文件,赋予参数 —>java package.class i am trying会输出 args[0]:i,args[1]:am
可变参数
public static void method( int(类型) num(…参数) )
{
for(int i=1;i<num.length;i++)
{
if(num[i]>0)
result = num [i] //说白了其实就是个数组
}
}
//一个方法中只能指定一个可变参数,也是最后一个参数,任何普通参数必须在它之前声明。例:method(char s,int …num);
递归
递归头:什么时候不调用自身方法。如果没有头,将陷入死循环。
递归体:什么时候需要调用自身方法
例: 阶乘的实现
public static int f( int n)
{
if (n==1)
return 1;
else
return n*f(n-1);
}
数组
1、数组的声明,int [] nums;
2、数组的创建,nums = new int [10]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
// 数组本身就是对象(Java中对象是保存在堆中的),数组元素相当于成员变量
3、Arrays 类
Arrays类中都是static修饰的静态方法,在使用时可以直接用类名进行调用,而 **不用(不是不能)**使用对象来调用;
常用方法:
//打印方法
Arrays.tostring()
//排序方法
Arrays.sort() —>升序
//给数组赋值
fill()
//比较数组
equals() —>比较元素值是否相等
//查找数组元素
binarysearch() —>对排序好的数组进行二分查找法操作
4、稀疏数组(自己创建一个数组记录)
适用条件: 元素中大部分是重复或没有意义的数据
处理方式:
1)记录数组一共有几行几列,有多少不同值
2)把具有不同值的元素和行列及值记录在一个小规模的数组中,缩小程序规模
封装
1、特点:
高内聚:类的内部数据操作细节自己完成,不允许外部干涉
低耦合:仅暴露少量方法给外部使用
2、应禁止直接访问一个对象中的数据的实际表示,而是通过操作接口来访问
3、属性私有,get/set
4、优先级 :public > protected >default(不加修饰符,默认的) >private
构造器
1、创建new对象时实际调用了构造器
2、一个类要写有参构造必须先有一个无参构造,否则父类没有无参构造子类也无法创建一个无参
继承
父类私有的东西无法继承
Super:
1、调用子类构造方法时,会先调用父类的无参构造方法(构造器),所以调用父类构造器在子类构造器的之前
2、super和this不能同时调用构造方法,两者需要在第一行
3、父类没有无参构造时,子类也没法写无参构造
多态
1、多态即同一方法可以根据发送对象的不同而采用多种不同的行为方式
2、存在条件:有继承关系;子类重写;上转型对象
3、多态时方法的多态,属性没有多态
注意:
1、// A a ;是定义A类 // new A() ; 是创建A类的对象
2、重写时修饰符的范围可以扩大但不能缩小,抛出的异常范为与之相反
3、static,private方法不能被重写
4、父类转换为子类—>向下转型 ,自动转换(高到低), B b = new A()
子类转换为父类 —> 向上转型 ,强制转换(低到高), (B) a = new B()
main{
A a = new A()
B b = new A()//子类的上转型对象,父类的引用指向了子类
}
class A extends B {
(static) void method {
println ( A )
}
}
class B {
(static) void method {
println ( B )
}
}
代码分析:
1、当方法是static方法时 , 输出—> A ,B
2、当方法是非static方法时 , 输出 —> A , A
1、static静态方法是类的方法,非静态方法是对象的方法。
2、有static时,b会调用B类的方法,因为b是用B类定义的。
3、没有static时,b调用的是对象的方法,而b是用A类new创建的,即b是A类的对象,所以调用了A类的方法。
instanceof
语法: 类型A instanceof 类型B —> 判断A,B是否存在继承关系,返回true或false
代码块
1、匿名代码块 class A { { } }
2、静态代码块 static {}
3、构造方法 A(){}
执行顺序: 静态代码块>匿名代码块>构造方法
拓展:静态导入包: import static java.package—>原来:Math.random()/Math.PI要有一个Math.调用 ; 导入后:random()/PI直接用
内部类
1、成员内部类:
class Out{
class In {}
}
内部类可以获得外部类的私有属性,方法
2、静态内部类(类用static修饰)
静态类无法访问非静态类属性
3、局部内部类
main/public void method(){
class In{}
}
4、匿名内部类
没有类的名称,必须借助接口或者父类
class B implements A{
main {
new A().method; //本来应该是A 类名 = new A(); 再用类名调用方法,但这里没有命名,只是创建了一个对象
a = new A(){
void method(){}
} //这里也是用未声明的a来承接A,借着创建其方法
}
}
class A{
method();
}
接口:
class A{
interface B{
method(){};
}
B b=new B(){
@override
method(){};
}
}
异常
1、异常分为Error和Exception
2、try{
if(){ throw …}
//监控区域
正常时执行
}
catch{
//捕获异常
异常时执行
}
finally{
//善后处理
可有可无
}
3、主动抛出异常 :
void method(){
if(){
throw new Exception() 一般在方法中使用
} }
假设在这个方法中,处理不了异常,方法上抛出异常
void method throws Exception (){
}
4、自定义异常类
class Myexception extends exception{}
出现异常时尽量去解决异常,而不仅仅是**e.printStackTrace()**将错误打印出来
二、进阶部分
线程
注意:线程并发:多个线程访问同一个对象;线程并行:多个任务,创建多个线程
callable接口
特殊点:重写call方法
//创建执行服务
ExecutorService es = Executors.newFixedThreadPool(线程数量);
//提交执行
Future <类型> res = es.submit(对象名);
获取结果
// int res = r.get();
关闭服务
//es.shutdownNow();
好处:
可以定义返回值 在call方法里;
可以抛出异常;
静态代理
1、真实对象和目标对象都要实现同一个接口
2、代理对象代理真实角色,调用了真实对象的方法
代理对象可以做真实对象很多做不了的事(可以实现自己的一些方法等),真实对象专注做自己的事
例:
interface Marry{
void Happy(){};
}
class You implements Marry{
void Happy(){
println(yes);
};
}
class Wedding implements Marry {
private Marry target;
Wedding(Marry target){
this.target = target;
}
void Happy(){
this.target.Happy(); //真实对象的调用
ownmethod(){};
}
void ownmethod(){};
}
new thread (目标对象 );也是代理
静态方法可以直接在主方法中调用
lambda表达式
1、目的:为了简化程序,避免内部类过多
2、属于函数式编程,前提:函数式接口:只包含唯一的抽象函数
interface A{void methods}
接口类型 命名 = (参数) -> {};
A a = (int i) -> {};
//简化1:参数类型
a =(i) ->{};
//简化2:简化括号
a = i->{};
//简化3:去掉花括号
a = i-> 代码体; 只能有一行代码时可以应用简化3
注意:
Class A{
for( int i = 1 ; i<=10 ; i++){
new thread ( ( ) ->{} ) .start ;
} }
// 这里的lambda本质上是一个接口类,而且还是个内部类无法直接使用外部类局部变量 , 如果使用必须用 final定义
原因:
- 匿名内部类访问的局部变量并不是真正的局部变量,而是局部变量的值拷贝。也就是说在匿名内部类中修改局部变量的值,无法影响到外部方法中的局部变量。
- 因此为了保证匿名内部类和外部方法中访问的局部变量的一致性,局部变量必须使用final修饰。
补充:在JDK8之后,匿名内部类引用外部变量时虽然不用显式的用final修饰,但是这个外部变量必须和final一样,不能被修改(这是一个坑)。解决方案:可以通过定义一个相同类型的变量b,然后将该外部变量赋值给b,匿名内部类引用b就行了,然后就可以继续修改外部变量。
所以对源码修改 —>
Class A{
for( int i = 1 ; i<=10 ; i++){
final int temp = i ;
new thread ( ( ) ->{} ) .start ;
} }
多线程的方法
方法 | 说明 |
---|---|
setPriority (int newPriority) | 改变线程的优先级 |
static void sleep (long millis) | 指定毫秒数休眠 |
void join() | 等待该线程终止 |
static void yield() | 暂停当前正在执行的线程对象,并执行其他线程 |
void interrupt() | 中断线程,别用这个方式 |
boolean isAlive() | 测试线程是否处于活动状态 |
1、停止进程:JDk停止的方法不推荐使用,都是强制性的,过期了
**建议使用一个标志位进行终止变量,当flag = false时,线程自动停止,不建议死循环 **
2、主方法本身就是一个线程,即主线程,可调用线程的方法
3、调用方法:new Thread(对象) . 方法名 或 创建 Tread类的一个对象,并传递继承接口的对象参数 //Thred thread =new Thread(duixiang) 再用thread直接调用方法即可 -->接口方式;
4、在定义的方法或run方法里规定执行的线程操作: Thread . 方法
5、线程可以用lambda简化:
main{
// Thread thread = new Thread( () -> {
代码体
} )
}
线程休眠sleep
1、每个对象都有一个锁,sleep不会释放锁
2、抛出InterruptedException异常
3、可以放大问题的发生性
线程礼让yield
1、作用:让当前正在执行的线程暂停,但不阻塞,由运行状态转为就绪状态
2、让CPU重新调度,礼让不一定成功,看CPU心情
合并线程Join
作用:待此线程完成后,再执行其他线程,其他线程阻塞(类似于插队)
线程状态
共5个状态:
观察状态方法, Thread.State state= thread.getState();
常用语法: 更新线程状态 -> state = thread.getState();
线程只要不终止的循环 -> while(state != Thread.State.TERMINATE {}
输出结果 -> println(state)
线程的优先级
优先级 1~10,数字越大优先级越高,优先级越高获得调度的概率越高,不在数字范围内会报错.
10 == Thread.MAX_PRIORITY; 1== Thread.MIN_PRIORITY ;main方法 == 5 ==Thread.NORM_PRIORITY
设置优先级 thread.setPriority(数字)
守护(daemon)线程
1、线程分为守护线程和用户线程
2、虚拟机必须确保用户线程执行完毕,不用等待守护线程执行完毕,如后台记录操作日志,监控内存,垃圾回收等待
3、Thread.daemon(true/false) , 返回值为布尔型,默认是false,表示是用户线程,正常的线程都是用户线程
线程同步(synchronized)
形成条件:队列+锁
会解决安全问题,线程并发时,一个线程获得对象的排它锁,独占资源,其他线程需等待,使用后释放锁即可
存在问题:性能降低问题(多个线程不能同时执行);性能倒置问题(优先级低的拿到锁)
同步方法
1、方法中的使用:
类似于private关键字来保证数据对象只能被方法访问,synchronized方法控制对对象的访问,每个synchornized方法必须获得调用该方法的对象的锁才能执行。否则会线程阻塞,方法一旦执行,就独占该锁,直到方法返回释放锁,后面阻塞的线程获得锁,继续执行,所以若将一个大的方法申明为synchornized会影响效率
方法里面需要修改内容的才需要锁,锁的太多,浪费资源
2、对象中的使用:
synchornized默认锁的是this.,类的本身
利用同步块:
synchornized (Obj) {} Obj为同步监视器
Obj可以是任何对象,但是推荐使用共享资源作为同步监视器;同步方法无需指定同步监视器,因为同步方法的同步监视器就是this,这个对象本身,或者是class,保证这个类只有一个
补充:CopyOnWriteArraylist泛型是JUC并发包的安全类型的集合
死锁
多个线程互相有对方需要的资源,然后形成僵持
产生条件:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来
LOCK锁(显示对象同步锁)
1、属于JUC包
2、ReentrantLock类(可重入锁)实现了Lock
3、一般与trycatchfinall联用:
void method(){
lock.lock();//上锁
try{
//保证线程安全的代码;
}
finally{
lock.unlock();//解锁
如果同步代码有异常,要将unlock()写入finally语句块
}
}
synchornized与Lock的对比:
线程通信
在生产者消费者问题中,仅有synchornized是不够的:
1、synchornized不能实现不同线程之间的消息传递(通信)
2、synchornized可阻止并发更新同一个共享资源,实现了同步
解决通信的方法:
方法名 | 作用 |
---|---|
wait() | 表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁 |
wait(long timeout) | 指定等待的毫秒数 |
notify() | 唤醒一个处于等待状态的线程 |
notifyAll() | 唤醒同一个对象上所有调用的wait()方法的线程,优先级高的线程优先调度 |
注意:均为Object类的方法,都只能在同步方法或者代码块中使用
生产者消费者问题
-> 利用缓冲区执行:管道法
->标志位解决:信号灯法
线程池
注解
作用:
1、注解(Annotation)不是程序本身,可以对程序做出解释(这一点跟注释(comment)没有什么区别)
2、可以被其他程序(比如:编译器)读取
格式:
@注释名,还可以添加一些参数值 如:@SuppressWarning(value=“unchecked”)
使用:
可以附加在package , class , method , field(字段)等,可以通过反射机制实现访问
内置注解
元注解
元注解就是负责注释其他注解
//定义一个注解
//Target 表示我们的注释可以用在哪些地方
@Target(value = {ElementType.METHOD,ElementType.TYPE})
//Retention 表示我们的注解在什么地方还有效
// runtime > class >sources
@Retention (value = RetentionPolicy.RUNTIME)
//Documented 表示是否将我们的注解生成在javadoc中
@Documented
//Inherited
@Inherited
@interface Annotation{}
以添加一些参数值 如:@SuppressWarning(value=“unchecked”)
使用:
可以附加在package , class , method , field(字段)等,可以通过反射机制实现访问
内置注解
[外链图片转存中…(img-inDObZpd-1626173877274)]
元注解
元注解就是负责注释其他注解
[外链图片转存中…(img-O0MYeXPI-1626173877274)]
//定义一个注解
//Target 表示我们的注释可以用在哪些地方
@Target(value = {ElementType.METHOD,ElementType.TYPE})
//Retention 表示我们的注解在什么地方还有效
// runtime > class >sources
@Retention (value = RetentionPolicy.RUNTIME)
//Documented 表示是否将我们的注解生成在javadoc中
@Documented
//Inherited
@Inherited
@interface Annotation{
// 注释的参数:参数类型+参数名+() deafault " " 代表默认值不写就代表默认值为空
1、如果没有默认值,就必须给注解赋值
2、如果默认值为 -1,则代表不存在
3、只有一个值的情况下,建议用value —>String value() **可以在方法注解上省略value,即不用传参
}
例:
@Target(value = {ElementType.METHOD,ElementType.TYPE})
@Retention ( RetentionPolicy.RUNTIME)
@interface MYAnnotation{
string name() deafault “”;
int age();
int id () default -1;
-----> @MYAnnotation(age =18,name =“ADMC”)
public void test() {}
反射
1、Java因为有了反射,变成一门准动态语言。反射机制可以让程序在执行期间取得任何类的内部信息。并能直接操作任意对象的内部属性及方法
2、加载完类后,堆内存区会产生一个class对象,这个对象包含了完整的类的内部信息。**一个类在内存中只有一个class对象,一个类被加载后,类的整个结构都会被封装在class对象中
3、优点:可以动态创建对象和编译,体现出很大的灵活性;缺点:降低性能,反射基本上是一种解释操作,告诉jvm我们做什么并且它满足我们的要求,这类操作慢于直接执行相同的操作。
4、实体类:定义的一个类中只有属性,一般用pojo或entity表示
获得反射对象
1、Class c1 = Person.class
//已知具体的类,通过类的class属性获取,这种方式最安全可靠,程序性能最高
2、Class c2 =person.getClass()
//已知某个类的实例
3、Class c3 =Class.forName( “类的路径”)
//已知一个类的全类名,且在该类路径下,可以通过class类的静态方法forName()获取
4、内置基本数据类型可以直接用 类名.Type
//获取父类类型用getSuperclass()方法
5、还可以用ClassLoader
所有类型的class对象
1、有class的类型:
class:爱不累,成员(成员内部类,静态内部类),匿名内部类
接口,数组,enum枚举,注解,基本数据类型,void
2、只要元素类型与维度一样,就是同一个Class,用hashCode()方法可以帮助判断,若返回值相同,则一样
类加载内存分析
分析类的初始化
类加载器
1、获得系统类加载器:
ClassLoader system = ClassLoader.getSystemClassLoader();
2、获取系统类加载器的父类加载器—>扩展类加载器:
ClassLoader parent = SystemClassLoader.getParent();
3、获取扩展类加载器的父类加载器—>根加载器(c/c++)
ClassLoader boot = parent.getParent(); ---->null
扩充:双亲委派机制—>防止自定义的包与jdk内置的包重名
获取类的运行时结构
可以获取的有:实现全部接口,所继承的父类,全部的构造器(constructor),全部的方法,全部的字段(Field),注解等
例:
Class c = Class.forName(“路径”);
获取类的信息:(通过方法传参可以获得指定)
c.getName() //获得包名+类名
c.getSimpleName() //获得类名
c.getField() +for循环 //获得类的属性(例:int age,string name)
getDeclareField //获得全部属性
getmethods() //获得本类及其父类的全部public方法
getDeclareMethods() //获得全部方法
动态创建对象的执行方法
例:
Class c = Class.forName(“路径”);
Type n= n.newInstance() //若果知道啥是什么类型可以直接强转 例:User user =(User)c.newInstance()
通过反射操作方法:
Methods m = n.getDeclareMethods(name:“m”,String.class) //通过反射获取一个方法
m.invoke() //激活方法
println(n.方法)
通过反射操作属性:
Filed filed =c.getDeclareField()
filed.set(n,“name”)
//注意返回的是public类型,如果想也能返回private类型要通过setAccessible(true/flase)方法
setAccessible(true/flase)是程序的安全检测,true是关掉,false是打开
性能对比分析
普通方式调用>反射方式调用(关闭安全检测)>反射方式调用
获取泛型信息
泛型可作为传参和返回值
m.getGenericParameterTypes() //获得泛型的参数信息
m.getGenericExceptionTypes() //获得泛型的异常信息
m.getGenericReturnTypes() //获得泛型的返回值信息
方法返回的是Type类型
获取注释信息
ORM—>Object relationship Mapping //对象关系映射
例:对应表格,类与表对应,属性与字段对应,对象与记录对相应
//通过反射获得注解
Class c = Class.forName(“路径”)
Annotation annotations = c.getAnnotations()
Table table =(Table)c.getAnnotations(Table.class) //如果知道了什么类型,可以直接强转
//获得注解value的值
String value = Table.value
//获得类的指定注解
Filed f =c.getDeclareField(“属性”)
FiledTable fannotations =f.getAnnotations(FiledTable.class)
println( fannotations.注解属性 )