视频看的是狂神说Java
1.Ctrl + shift + esc
打开任务管理器
2.win + E
打开“我的电脑”
3.win + R
打开运行方式
4.ctrl + F4
快速关闭网页或者文件
5.shift + delete
永久删除文件
6.在任务管理器中将“Windows资源管理器”结束任务时,桌面将会消失。点击文件
中的运行任务
输入explorer
就会出现桌面。
cmd
+空格,即可进入控制台;[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZFcyQYxF-1637023966165)(java.assets/image-20210625111722301.png)]
开始 + windows系统 + 命令提示符 + 鼠标右键 + 更多 + 以管理员方式运行(可以获得最高权限)
#盘符切换 E: + 回车 #查看当前目录下的所有文件:dir #切换目录 cd /d f:\文件名 #返回上一级 cd .. #清楚屏幕 cls #退出终端 exit #查看ip ipconfig #打开应用 calc计算机 mspaint画图 notepad记事本 #ping 命令 ping www.baidu.com #创建文件夹 md 文件夹名称 #删除文件夹 rd 文件夹名称 #创建文件 cd>文件名.后缀 #删除文件 del 文件名.后缀
ipconfig/release
:释放全部(或指定)适配器的由DHCP分配的动态IP地址。此参数适用于IP地址非静态分配的网卡,通常和下文的renew参数结合使用。
ipconfig/renew
:为全部(或指定)适配器重新分配IP地址。此参数同样仅适用于IP地址非静态分配的网卡,通常和上文的release参数结合使用。
**1. 三个问题:**高可用、高性能、高并发
2. 版本:
J2SE:Java2标准版 J2ME:Java2移动版 J2EE:Java2企业版
简单性:比C++易理解、易操作
面向对象:万物皆可成对象
可移植性:一次编译,多次运行。借助的是Java虚拟机
高性能:
分布式:通过url可以链接网页
动态性:通过反射机制实现
多线程:实现实时和同时做不同事情
安全性:底层代码设置了很多关于安全技术,防漏洞技术
健壮性:运行代码会自主查看内存消耗情况,没有指针的到处引用现象
**JavaSE:**标准版(桌面程序,控制台开发…)
**JavaME:**嵌入式开发(手机,小家电…)
**JavaEE:**企业级开发(web端,服务器开发…)
JDK: Java Development Kit
JRE: Java Runtime Environment
JVM: Java Virtual Machine
.java文件(源文件) -> (Java编译器)—> .class文件(字节码) —> 类装载器 —> 字节码校验器 —> 解释器 —> 操作系统平台
创建空的project后,随后点击file
,然后点击创建module
,在project Structure
里指定JDK版本和下面对应的解释等级,例如JDK是1.8,则下面对应的数字为8
单行注释:// 多行注释:/* */
文本注释:
/** * @Description 描述代码功能信息 * @Author 编写代码的作者是谁 */
**强类型语言:**所有变量都必须先定义后才能使用
弱类型语言:
类别:
基本类型:
**整数类型:**byte short(2) int(4) long(8)后面加L
**浮点类型:**float(4) 后面加F double(8)
**字符类型:**char(2)
**Boolean类型:**true或false
类型转换:
低----》 高
byte short char int long float double
强制转换 (类型)变量名 高—》低
自动转换 低----》 高
注:不能对布尔值进行转换
不能把对象类型转换为不相干的类型
在把高容量转换到低容量的时候强制转换
转换的时候可能存在内存溢出或精度问题
1B (byte,字节) = 8 bit(位)
引用类型:
类 接口 数组
类变量: 前面有static修饰 static double salary = 2500;
实例变量: 赋初值,从属于对象,如果不初始化则为默认值,0,0.0,false(boolean),null(string)
局部变量: 定义在方法里,使用前必须声明和初始化
类名: 首字母大写和驼峰原则
**方法名:**首字母小写和驼峰原则
final 常量名 = 值;
常量名一般使用大写字符
修饰符不区分前后,public,static,final
^ 异或 相同为0,不同为1
<< 代表左移,*2 2<<3 =16
>> 代表右移 /2
没有long时,所有非int类型转为int类型
“”+a+b 输出为1020
a+b+"" 输出为30
命令行生成JavaDoc文档 javadoc -encoding UTF-8 -charset UTF-8 文件名.java
Scanner scanner = new Scanner(System.in); // 从键盘接受数据 Scanner.hasnext() // 判断接受的数据是否为空,以空格作为结束标志 Scanner.hasNextLine() // 判断接受的数据是否为空,以回车符为结束标志 scanner.close(); // 用完记得关闭
int i = scanner.nextInt(); // 接受的是整数数据 float f = scanner.nextFloat(); // 接受的是浮点数据 String str = scanner.next(); 获取输入的字符串 next() 以空格符结束,nextLine() 以回车符结束 hasNext(),hasNextLine() 判断是否还有输入的数据
if选择结构 For循环
Switch结构
switch语句中的变量类型可以是:byte、short、int、string、枚举或者char;
从JavaSE7开始,switch支持字符串String类型了
default:前面case全没有匹配成功后,才输出默认语句,否则不输出
增强for循环
While结构 break continue
DoWhile结构
goto
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f0rrLfkn-1637023966170)(java.assets/image-20210704104146461.png)]
outer:for (int i = 100; i < 205; i++){ for (int j = 2; j < i / 2; j++){ if (i % j == 0){ continue outer; // 当不满足质数要求时候,跳到外面循环outer } } System.out.println(i + " "); }
public void min(int x,int ... y)
1. 静态初始化
int[] a = {1,2,3};
2. 动态初始化
int[] a = new int[10];
3. 默认初始化
数组是引用类型,它的元素相当于类的实例变量,已经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nr3t25jn-1637023966176)(java.assets/image-20210705160929729.png)]
数组的工具类java.util.Arrays
Arrays类中的方法都是static修饰的静态方法,使用时直接用类名进行调用
常用的功能:
给数组赋值:
Arrays.fill();
对数组排序:
Arrays.sort();
比较数组:
Arrays.equals();
查找数组元素:
Arrays.binarySearch();
输出数组:
Arrays.toString();
封装:高内聚、低耦合
继承
关键字:extends
Java中类只有单继承,没有多继承!
子类的无参构造函数会首先默认调用父类的无参构造函数
super注意点:
a. super调用父类的构造方法,必须在构造方法的第一个;
b. super必须只能出现在子类的方法或者构造方法中;
c. super和this不能同时调用构造方法。
super与this:
代表的对象不同:
a. this:本身调用者这个对象
b. super:代表父类对象的应用
前提:
a. this:没有继承也可以使用
b. super:只能在继承条件才使用
构造方法:
a. this():本类的构造
b. super():父类的构造
重写:
如果父类和子类中的方法都有static修饰时,方法的调用只和左边定义的数据类型有关;
如果父类和子类中的方法都没有static修饰时,方法的调用只和右边new创建的对象和定义的数据类型有关;
多态
多态是方法的多态,属性没有多态;
父类与子类存在联系,否则会报:ClassCastException
存在条件:继承关系,方法需要重写,父类引用指向子类对象!
当子类没有重写父类的方法时,此时调用的是父类方法;当子类重写了父类方法时,此时调用的是子类方法;当调用子类独有的方法时,此时需要父类引用进行类型强制转换。
不能重写的方法有:
public class Person{ // 匿名函数 { System.out.println("匿名函数"); } // 静态代码块 static { System.out.println("静态代码块"); //只执行一次 } // 无参构造函数 pra01(){ System.out.println("无参构造函数"); } }
//输出的结果为: 静态代码块 匿名函数 无参构造函数
public abstract class Person { //抽象方法 public abstract void run(); //正常方法 public void go(){ System.out.println("正常的方法"); } }
**普通类:**只有具体实现
**抽象类:**具体实现和规范(抽象方法)都有
**接口:**只有规范
public class Outer{ private int id = 10; public void out(){ System.out.println("这是外部类的方法"); } //成员内部类 public class Inner{ public void in(){ System.out.println("这是内部类的方法"); } //获得外部类的私有属性 public void GetID(){ System.out.println(id); } } }
Outer outer = new Outer(); //通过外部类来实例化内部类 Outer.Inner inner = outer.new Inner(); inner.getID();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-29ZZUCwW-1637023966180)(java.assets/image-20210708092755954.png)]
Error
Exception
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ivQ29Y75-1637023966183)(java.assets/image-20210708093551468.png)]
两大类
异常处理五个关键字:try catch finally throw throws
finally:不管是否出现异常,都会执行finally里的相关语句
当出现多个catch语句时,从上往下范围依次变大,最后只有一个起作用,其他catch语句不输出
idea快捷键:ctrl + alt + T
// 方法上抛出异常,使用throws public void test(int a, int b) throws ArithmeticException{ if(b == 0){ // 主动抛出异常,一般在方法中使用throw throw new ArithmeticException(); } }
**进程:**系统资源分配的单位
**线程:**CPU调度和执行的单位。
方法一:继承Thread类
public class TestThread1 extends Thread{ //重写run方法 public void run(){ for (int i = 0; i < 10; i++){ System.out.println("代码在跑步。。。。"); } } public static void main(String[] args) { TestThread1 thread1 = new TestThread1(); thread1.start(); for (int i = 0; i < 1000; i++){ System.out.println("main主线程"); } } }
线程不一定立即执行,CPU安排调度
注意:
如果main函数里调用的是 thread1.start()语句,则main主线程和分支线程同时交替执行 如果main函数里调用的是 thread1.run()语句,则先执行创建的分支线程,再执行main主线程
方法二:实现 Runnable接口
推荐使用Runnable对象,因为Java单继承的局限性
public class TestThread2 implements Runnable{ public void run(){ .... } public static void main(String[] args) { TestThread2 thread2 = new TestThread2(); new Thread(thread2).start(); // 将实现Runnable接口的对象放入Thread构造函数中进行启动 .... } }
常用的方法
Thread.currentThread().getName(); //获取当前线程的名字 Thread.sleep(); // 让线程睡眠,单位毫秒
方法三:实现 Callable接口
ExecutorService ser = Executors.newFixedThreadPool(3); // 3代表创建线程的个数
Future<Boolean> result1 = ser.submit(t1); // 泛型<>里的类型与实现Callable接口返回值类型一致
boolean r1 = result1.get(); // 与实现Callable接口返回值类型一致
ser.shutdownNow();
其实质属于函数式编程
(params) -> expression[表达式]
(params) -> statement[语句]
(params) -> {statements}
总结:
例子
package com.ty.Thread_prac.lamda; public class Testlambda1 { // 3.静态内部类 static class Like2 implements Ilike{ @Override public void lambda() { System.out.println("i like lambda2"); } } public static void main(String[] args) { Ilike like = new Like(); like.lambda(); like = new Like2(); like.lambda(); // 4.局部内部类 class Like3 implements Ilike{ @Override public void lambda() { System.out.println("i like lambda3"); } } like = new Like3(); like.lambda(); // 5.匿名内部类,没有类的名称,只能借助接口或者父类 like = new Ilike() { @Override public void lambda() { System.out.println("i like lambda4"); } }; like.lambda(); // 6.用lambda简化 like = ()->{ System.out.println("i like lambda5"); }; like.lambda(); // 7.lambda再简化 like = ()-> System.out.println("i like lambda6"); like.lambda(); } } // 1.定义一个函数式接口 interface Ilike{ void lambda(); } // 2. 实现类 class Like implements Ilike{ @Override public void lambda() { System.out.println("i like lambda"); } }
创建状态、就绪状态、阻塞状态、运行状态、死亡状态
Thread t = new Thread()线程对象一旦创建就进入到了新生状态
当调用start() 方法,线程立即进入就绪状态,但不意味着立即调度执行
当调用sleep,wait或同步锁定时,线程进入阻塞状态,就是代码不往下执行,阻塞时间解除后,重新进入就绪状态,等待cpu调度执行
进入运行状态,线程才真正执行线程体的代码块
线程中断或者结束,一旦进入死亡状态,就不能再次启动
方法 | 说明 |
---|---|
setPriority(int newPriority) | 更改线程的优先级 |
static void sleep(long millis) | 在指定的毫秒数内让当前正在执行的线程休眠 |
void join() | 等待该线程终止 |
static void yield() | 暂停当前正在执行的线程对象,并执行其他线程 |
void interrupt() | 中断线程,别用这个方式 |
boolean isAlive() | 测试线程是否处于活动状态 |
模拟倒计时
public class TestSleep { public static void main(String[] args) { try { tenDown(); } catch (InterruptedException e) { e.printStackTrace(); } } // 模拟倒计时 public static void tenDown() throws InterruptedException{ int num = 10; while(true){ Thread.sleep(1000); System.out.println(num--); if (num < 0){ break; } } } }
打印当前系统时间
public static void main(String[] args) { // 打印当前系统时间 Date startTime = new Date(System.currentTimeMillis()); // 获取系统当前时间 while (true){ try { Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime)); startTime = new Date(System.currentTimeMillis());//更新当前时间 } catch (InterruptedException e) { e.printStackTrace(); } } }
public class TestYield { public static void main(String[] args) { MyYield myi = new MyYield(); new Thread(myi,"a").start(); new Thread(myi,"b").start(); } } class MyYield implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName() + "线程成功了!"); Thread.yield(); System.out.println(Thread.currentThread().getName() + "线程成功了!"); } }
thread.join()
Thread.State state = thread.getState() // 状态有NEW RUNNABLE BLOCKED WAITING TIMED_WAITING TERMINATED
Thread.MIN_PRIORITY = 1; Thread.MAX_PRIORITY = 10; Thread.NORM_PRIORITY = 5;
getPriority() setPriority(int xxx)
优先级低只是意味着获得调度的概率低,并不是优先级低就不会被调用了,这都看cpu的调度
优先级的设定建议再sart()调度前
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕
如,后台记录操作日志,监控内存,垃圾回收等待
// 默认是false表示是用户线程,正常的线程都是用户线程 Thread.setDaemon(true)
**并发:**同一个对象被多个线程同时操作
锁机制synchronized导致的一些问题:
1. 一个线程持有锁会导致其他所有需要此锁的线程挂起; 2. 在多线程竞争下,加锁,释放锁会导致比较多的上下文切换 和 调度延时,引起性能问题; 3. 如果一个优先级高的线程等待一个优先级低的线程释放锁 会导致优先级倒置,引起性能问题
产生死锁的四个必要条件:
注意:
只要破坏其中任意一个或多个条件就可以避免死锁发生
class TestLock implements Runnable{ int tickNums = 10; // 定义lock锁,ReentrantLock可重用锁 private final ReentrantLock lock = new ReentrantLock(); @Override public void run() { while (true){ try { lock.lock(); // 加锁 if (tickNums > 0){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(tickNums--); }else { break; } } finally { // 解锁 lock.unlock(); } } } }
如果同步代码有异常,要将unlock()写入finally语句块
应用场景:生产者和消费者问题
解决方式1:
并发写作模型“生产者/消费者模式” -->管程法
生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据
package com.ty.Thread_prac.state; // 测试:生产者消费者模型-->利用缓冲区解决:管程法 // 生产者,消费者,产品,缓冲区 public class TestPC { public static void main(String[] args) { SynContainer container = new SynContainer(); new Productor(container).start(); new Consumer(container).start(); } } // 生产者 class Productor extends Thread{ SynContainer container; public Productor(SynContainer container) { this.container = container; } @Override public void run() { for (int i = 0; i < 100; i++) { container.push(new Chicken(i)); System.out.println("生产了" + i + "只鸡"); } } } // 消费者 class Consumer extends Thread{ SynContainer container; public Consumer(SynContainer container) { this.container = container; } @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("消费了-->"+container.pop().id+"只鸡"); } } } // 产品 class Chicken{ int id; public Chicken(int id) { this.id = id; } } // 缓冲区 class SynContainer{ Chicken[] chickens = new Chicken[10]; int count = 0; // 生产者放入产品 public synchronized void push(Chicken chicken){ //如果容器满了,就需要等待消费者消费 if (count == chickens.length){ //通知消费者消费,生产者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 如果没有满,我们就需要丢入产品 chickens[count]=chicken; count++; // 可以通知消费者消费了 this.notifyAll(); } // 消费者消费产品 public synchronized Chicken pop(){ // 判断能否消费 if (count == 0){ // 等待生产者生产,消费者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 如果可以消费 count--; Chicken chicken = chickens[count]; // 吃完了,通知生产者生产 this.notifyAll(); return chicken; } }
解决方式2:
并发协作模型“生产者/消费者模式” -->信号灯法
package com.ty.Thread_prac.state; public class TestPC2 { public static void main(String[] args) { TV tv = new TV(); new Player(tv).start(); new Watcher(tv).start(); } } // 生产者--> 演员 class Player extends Thread{ TV tv; public Player(TV tv){ this.tv = tv; } @Override public void run() { for (int i = 0; i < 20; i++) { if (i % 2 ==0){ this.tv.play("快乐大本营播放中"); }else{ this.tv.play("抖音:记录美好生活"); } } } } // 消费者--> 观众 class Watcher extends Thread{ TV tv; public Watcher(TV tv){ this.tv = tv; } @Override public void run() { for (int i = 0; i < 20; i++) { tv.watch(); } } } // 产品 -- > 节目 class TV{ // 演员表演,观众等待 T // 观众观看,演员等待 F String voice;// 表演节目 boolean flag = true; // 表演 public synchronized void play(String voice){ if (!flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("演员表演了:" + voice); // 通知观众 this.notifyAll(); // 通知唤醒 this.voice = voice; this.flag = !this.flag; } // 观看 public synchronized void watch(){ if (flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("观看了:" + voice); // 通知演员表演 this.notifyAll(); this.flag = !this.flag; } }
提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具
JDK5.0起提供了线程池相关API:ExecutorService和Executors
ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor
Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池
package com.ty.Thread_prac.state; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TestPool { public static void main(String[] args) { // 1.创建服务,创建线程池,参数为线程池大小 ExecutorService service = Executors.newFixedThreadPool(10); service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); // 2.关闭连接 service.shutdown(); } } class MyThread implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }
线程总结:
public class ThreadNew{ pulic static void main(String[] args){ new MyThread1().start(); new Thread(new MyThread2()).start(); FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread3()); new Thread(fatureTask).start(); try{ Intrger integer = futureTask.get(); System.out.println(integer); }catch(InterruptedException e){ e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } } } //1、继承Thread类 class MyThread1 extends Thread{ @override public void run(){ System.out.println("MyThread1"); } } //2、实现Runnable接口 class MyThread2 imlpements Runnable{ @override public void run(){ System.out.println("MyThread2"); } } //3、实现Runnable接口 class MyThread3 implements Callable<Integer>{ @override public Integer call() throes Exception{ System.out.println("MyThread3"); return 100; } }
**作用:**可以被其他程序(编译器)读取
格式:@注释名
**使用:**通过反射机制编程实现对元数据的访问
**@Override:**定义在java.lang.Override中,表示一个方法声明打算重写超类中的另一个方法声明(作用在方法)
**@Deprecated:**定义在java.lang.Deprecated中,不鼓励使用(作用在方法、属性和类)
**@SupperessWarnings:**定义在java.lang.SupperessWarnings中,用于抑制编译时的警告信息,这个需要参数(“all” “unchecked” )
// @Target 表示我们的注解在什么地方起作用 @Target(value ={ElementType.METHOD,ElementType.TYPE}) // @Retention 表示我们的注解在什么地方还有效 SOURCE<CLASS<RUNTIME @Retention(value= RetentionPolicy.RUNTIME) // @Documented 表示是否将我们的注解生成在Javadoc中 @Documented // @Inherited 子类可以继承父类的注解 @Inherited //定义一个注解,直接写内部类 @interface MyAnnotation{}
@interface
自定义注解时,自动继承了java.lang.annotation.Annotation接口例子
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; public class Test03 { // 注解可以显示赋值,如果没有默认值,我们就必须给注解赋值 @MyAnnotation02(age = 18,name = "李四") //有默认值可以不写 public void test(){} @MyAnnotation03("赵四") //默认值只有一个,用value表示,使用时可以省略 public void test02(){} } @Target({ElementType.TYPE,ElementType.METHOD}) //作用在类和方法上 @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation02{ // 注解的参数:参数类型 + 参数名(); String name() default ""; int age() default 0; int id() default -1; // 如果默认值为-1,代表不存在 String[] schools() default {"清华大学","北京大学"}; } @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation03{ // 注解的参数:参数类型 + 参数名(); String value(); }
动态语言
静态语言
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sjhcoixr-1637023966187)(java.assets/image-20210806210619030.png)]
**优点:**可以实现动态创建对象和编译,体现出很大的灵活性
**缺点:**性能较慢
(原因:反射是一种解释操作,告诉JVM希望做什么并让JVM满足要求,这类操作总是慢于直接执行相同的操作)
package com.ty.JavaPractice.annotation; public class Test04 { public static void main(String[] args) throws ClassNotFoundException { //通过反射获取类的class对象 Class c1 = Class.forName("com.ty.JavaPractice.annotation.User"); System.out.println(c1); // 一个类在内存中只有一个class对象 // 一个类被加载后,类的整个结构都会被封装在class对象中 Class c2 = Class.forName("com.ty.JavaPractice.annotation.User"); Class c3 = Class.forName("com.ty.JavaPractice.annotation.User"); Class c4 = Class.forName("com.ty.JavaPractice.annotation.User"); System.out.println(c2.hashCode()); System.out.println(c3.hashCode()); System.out.println(c4.hashCode()); } }
在Object类中定义了以下的方法,此方法将被所有子类继承
public final Class getClass()
反射的本质:通过对象反射求出类的名称
类的属性、方法和构造器、实现的接口
方法名 | 功能说明 |
---|---|
static Class.forName(String name); | 返回指定类名name的Class对象 |
Object newInstance(); | 调用缺省构造函数,返回对象的一个实例 |
getName(); | 返回此Class对象所表示的实体(类、接口、数组类或void)的名称 |
Class getSupperClass(); | 返回当前Class对象的父类的Class对象 |
Class[] getinterfaces() | 获取当前Class对象的接口 |
ClassLoader getClassLoader() | 返回该类的类加载器 |
Constructor[] getConstructors() | 返回一个包含某些Constructor对象的数组 |
Method getMethod(String name,Class… T) | 返回一个Method对象,次对象的形参类型为paramType |
Field[] getDeclaredFields() | 返回Field对象的一个数组 |
Class clazz = Student.class;//通过类名.class获得 clazz输出为:class demo01.Student
Class clazz = person.getClass();//通过对象获得
Class clazz = Class.forName("demo01.Student");//通过forname获得
**class:**外部类、成员(成员内部类、静态内部类),局部内部类,匿名内部类
**interface:**接口
**[]:**数组
**enum:**枚举
**annotation:**注解@interface
**primitive type:**基本数据类型
void
// 类 Class c1 = Object.class; // 接口 Class c2 = Comparable.class; // 一维数组 Class c3 = String[].class; // 二维数组 Class c4 = int[][].class; // 注解 Class c5 = Override.class; // 枚举 Class c6 = ElementType.class; // 基本数据类型 Class c7 = Integer.class; // void Class c8 = void.class; // Class Class c9 = Class.class;
注:只要元素类型与维度一样,就是同一个Class
package com.ty.JavaPractice.annotation; public class Test05 { public static void main(String[] args) { A a = new A(); System.out.println(A.m); /* 1.加载到内存,会产生一个类对应Class对象 2.链接,链接结束后m=0,赋默认值; 3.初始化 <clinit>(){ System.out.println("A的静态代码块区域"); m=10; m=20; } 输出m=20 */ } } class A{ static { System.out.println("A的静态代码块区域"); int m = 10; } static int m = 20; public A(){ System.out.println("A类的无参构造函数初始化"); } }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-47l98Vsn-1637023966189)(java.assets/image-20210807094931326.png)]
类的主动引用(一定会发生类的初始化)
类的被动引用(不会发生类的初始化)
//测试类什么时候初始化 public class Test06 { static { System.out.println("main所在的类被加载"); } public static void main(String[] args) { //1.主动引用 Son son = new Son(); /** 输出结果为: main所在的类被加载 父类被加载 子类被加载 **/ } } class Father{ static int b = 1; static { System.out.println("父类被加载"); } } class Son extends Father{ static { System.out.println("子类被加载"); m = 10; } static int m =20; static final int M = 25;
public static void main(String[] args) throws ClassNotFoundException { //2.反射也会产生主动引用 Class.forName("com.ty.JavaPractice.annotation.Son"); /** * 输出结果为: * main所在的类被加载 * 父类被加载 * 子类被加载 */ }
public static void main(String[] args) throws ClassNotFoundException { // 3.不会产生类的引用 System.out.println(Son.b); /* 输出结果为: main所在的类被加载 父类被加载 1 */ }
public static void main(String[] args) throws ClassNotFoundException { Son[] array = new Son[5]; /** * 输出结果为; * main所在的类被加载 */ }
public static void main(String[] args) throws ClassNotFoundException { // 子类里的常量 System.out.println(Son.M); /* * 输出结果为: * main所在的类被加载 25 * */ }
**类加载器作用:**将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java,lang.Class对象,作为方法区中类数据的访问入口
**类缓存:**标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0bnQpFzD-1637023966191)(java.assets/image-20210807105911900.png)]
类型:
加载机制:
package com.ty.JavaPractice.annotation; public class Test07 { public static void main(String[] args) { // 获取系统类加载器 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); System.out.println(systemClassLoader); // jdk.internal.loader.ClassLoaders$AppClassLoader@3fee733d // 获取系统类加载器的父类加载器-->扩展加载器 ClassLoader parent = systemClassLoader.getParent(); System.out.println(parent); // jdk.internal.loader.ClassLoaders$PlatformClassLoader@723279cf // 获取扩展加载器的父类加载器-->根加载器 ClassLoader parent1 = parent.getParent(); System.out.println(parent1); // null //如何获取系统类加载器可以加载的路径 System.out.println(System.getProperty("java.class.path")); } }
package com.ty.JavaPractice.annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Test08 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException { Class c1 = Class.forName("com.ty.JavaPractice.annotation.User"); // 获得类的名字 System.out.println(c1.getName()); // 获得包名+类名 System.out.println(c1.getSimpleName()); // 获得类名 // 获得类的属性 System.out.println("===================="); Field[] fields = c1.getFields(); // 只能找到public属性 fields = c1.getDeclaredFields(); // 找到所有的属性 for (Field field : fields) { System.out.println(field); } System.out.println("===================="); // 获得指定的属性 Field name = c1.getDeclaredField("name"); System.out.println(name); // 获得类的方法 System.out.println("===================="); Method[] methods = c1.getMethods(); // 获得本类及其父类的全部public方法 for (Method method : methods) { System.out.println(method); } Method[] declaredMethods = c1.getDeclaredMethods();// 获得本类的所有方法 for (Method declaredMethod : declaredMethods) { System.out.println(declaredMethod); } // 获得指定方法 // 由于是重载,所以得指定参数 Method getName = c1.getMethod("getName", null); Method setName = c1.getMethod("setName", String.class); System.out.println(getName); // 获得指定的构造器 System.out.println("===================="); Constructor[] constructors = c1.getConstructors(); constructors = c1.getDeclaredConstructors(); for (Constructor constructor : constructors) { System.out.println(constructor); } // 获得指定的构造器 Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class); System.out.println(declaredConstructor); } }
package com.ty.JavaPractice.annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Test10 { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { // 获得class对象 Class c1 = Class.forName("com.ty.JavaPractice.annotation.User"); // 构造一个对象 User user1 = (User) c1.newInstance(); // 本质是调用了类的无参构造器 System.out.println(user1); // 通过构造器创建对象 Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class); User user2 =(User) constructor.newInstance("李四", 23, 2); System.out.println(user2); // 通过反射调用普通方法 User user3 = (User) c1.newInstance(); Method setName = c1.getDeclaredMethod("setName", String.class); // invoke:激活的意思(对象,”方法的值“) setName.invoke(user3,"赵四"); System.out.println(user3); // 通过反射操作属性 System.out.println("================================="); User user4 = (User) c1.newInstance(); Field name = c1.getDeclaredField("name"); // 私有属性需要关闭程序的安全检测,属性或方法的setAccessible(true) name.setAccessible(true); name.set(user4,"王五"); System.out.println(user4); } }
普通调用方法 最快
关闭Java语言检查进行反射调用,setAccessible(true) 其次
直接反射调用方法 最慢
Java采用泛型擦除的机制来引入泛型。
反射泛型相关的类:
package com.ty.JavaPractice.annotation; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; public class Test11 { public static void test01(Map<String,User> map, List<User> list){ System.out.println("test01"); } public Map<String,User> test02(){ System.out.println("test02"); return null; } public static void main(String[] args) throws NoSuchMethodException { Method test01 = Test11.class.getMethod("test01", Map.class, List.class); Type[] genericParameterTypes = test01.getGenericParameterTypes(); for (Type genericParameterType : genericParameterTypes) { System.out.println(genericParameterType); if (genericParameterType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } System.out.println("================================"); Method test02 = Test11.class.getMethod("test02", null); Type genericReturnType = test02.getGenericReturnType(); if (genericReturnType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } }
package com.ty.JavaPractice.annotation; import java.lang.annotation.*; import java.lang.reflect.Field; public class Test12 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class c1 = Class.forName("com.ty.JavaPractice.annotation.Student"); // 通过反射获得注解 Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } //输出结果:@com.kuang.reflection.TableA(value=db_student) // 获得注解的val值 TableA tableA = (TableA)c1.getAnnotation(TableA.class); String value = tableA.value(); System.out.println(value); // 获得指定的注解 Field name = c1.getDeclaredField("name"); FieldA annotation = name.getAnnotation(FieldA.class); System.out.println(annotation.columnName()); System.out.println(annotation.type()); System.out.println(annotation.length()); //输出为:db_name varchar 10 } } @TableA("db_student") class Student{ @FieldA(columnName = "db_name",type = "varchar",length = 10) private String name; @FieldA(columnName = "db_id",type = "int",length = 10) private int id; @FieldA(columnName = "db_age",type = "int",length = 10) private int age; public Student() { } public Student(String name, int id, int age) { this.name = name; this.id = id; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", id=" + id + ", age=" + age + '}'; } } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface TableA{ String value(); } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface FieldA{ String columnName(); String type(); int length(); }
float和double表示的长度都是优先的,存在舍入误差的情况,所以float和double类型的变量虽然赋予的值相等,但是二者比较则不会相等。
float f = 0.1f; double d = 1.0/10; System.out.println(f==d); // false
银行业务设计浮点数时,使用
BigDecimal
数学工具类
BigDecimal num1 = new BigDecimal("24"); BigDecimal num2 = new BigDecimal("2"); BigDecimal sum_result = num1.add(num2); // 加法 BigDecimal sub_result = num1.subtract(num2); // 减法 BigDecimal mul_result = num1.multiply(num2); // 乘法; BigDecimal abs_result = num1.abs(); // 绝对值 BigDecimal div_result = num1.divide(num2); // 除法;
编码Unicode: 占2字节 0~65536
转义字符:
\t 制表符
\n 换行
\u Unicode编码 \u0061表示16进制数,10进制为65
String str1 = new String("hello"); String str2 = new String("hello"); System.out.println(str1 == str2); //false; String str3 = "hello"; String str4 = "hello"; System.out.println(str3 == str4); // true
都继承的是抽象的字符串父类:AbstractStringBuilder
1. 线程安全
StringBuffer的所有公开方法都是synchronized修饰的,而StringBuilder并没有;因此StringBuffer是线程安全的,而StingBuilder是线程不安全的
2.缓冲区
StringBuffer每次获取toString都会直接使用缓冲区的toStringCache值来构造一个字符串;StringBuilder则每次都需要复制一次字符数组,再构造一个字符串
3.性能
由于StringBuilder没有线程安全,因此性能要远大于StringBuffer。
name;
}
public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", id=" + id + ", age=" + age + '}'; }
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableA{
String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldA{
String columnName();
String type();
int length();
}
# 面试 ## 基本数据类型 ### 浮点数 float和double表示的长度都是优先的,存在舍入误差的情况,所以float和double类型的变量虽然赋予的值相等,但是二者比较则不会相等。 ```java float f = 0.1f; double d = 1.0/10; System.out.println(f==d); // false
银行业务设计浮点数时,使用
BigDecimal
数学工具类
BigDecimal num1 = new BigDecimal("24"); BigDecimal num2 = new BigDecimal("2"); BigDecimal sum_result = num1.add(num2); // 加法 BigDecimal sub_result = num1.subtract(num2); // 减法 BigDecimal mul_result = num1.multiply(num2); // 乘法; BigDecimal abs_result = num1.abs(); // 绝对值 BigDecimal div_result = num1.divide(num2); // 除法;
编码Unicode: 占2字节 0~65536
转义字符:
\t 制表符
\n 换行
\u Unicode编码 \u0061表示16进制数,10进制为65
String str1 = new String("hello"); String str2 = new String("hello"); System.out.println(str1 == str2); //false; String str3 = "hello"; String str4 = "hello"; System.out.println(str3 == str4); // true
都继承的是抽象的字符串父类:AbstractStringBuilder
1. 线程安全
StringBuffer的所有公开方法都是synchronized修饰的,而StringBuilder并没有;因此StringBuffer是线程安全的,而StingBuilder是线程不安全的
2.缓冲区
StringBuffer每次获取toString都会直接使用缓冲区的toStringCache值来构造一个字符串;StringBuilder则每次都需要复制一次字符数组,再构造一个字符串
3.性能
由于StringBuilder没有线程安全,因此性能要远大于StringBuffer。