[TOC]
JavaSE
win
md 创建文件件
dir 查看文件件内的文件属性
del 删除文件
rd 删除文件夹(文件夹内不能有文件)
文档注释
javadoc -d 生成文件夹名 -author -version 文件名
java API 文档
https://docs.oracle.com/javase/8/docs/api/ (v.8)
常用快捷键
ctrl + w 关闭当前窗口
ctrl + shift + w 关闭所有窗口
ctrl + alt + g 查看指定结构使用过的地方
end 直接定位到当前行的结尾
Ctrl + alt + v 自动补全 局部变量;
ctrl+alt+t 代码环绕
多态性
一个事物的多种形态
对象的多态性:父类的引用指向子类的对象,只适用于方法不适用于属性
多态的使用:当调用子父类同名参数的方法时,实际执行的是子类重写父类的方法—-虚拟方法调用(在编译期只能调用父类中声明的方法,在实际执行是的子类重写父类的方法)
使用前题:类的继承,方法的重写
向下转型
instanceof
a instanceof A ;判断对象a是否是类A的实例,如果是返回true否则返回false
如果A返回true ,a instanceof B也返回true,其中类B是类A的父类
Object
只声明了一个空参构造器
包装类
基本数据类型转换成包装类
Integer int1 = new Inetger(参数);
包装类转换成数据类型
Integer int1 = new Inetger(参数);
int i1 = int1.3intValue();
String 转换成 基本数据类型
假如是int则用 Integer.parseInt(参数);(包装类要和参数数据类型一致)
static
静态变量(static修饰时):多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用次静态变量时,是修改过了的。
随着类的加载而加载;
早于对象的创建,只要权限允许可以通过对象.static属性的方式调用;
存在于方法区的静态域中
静态方法(static修饰时):随着类的加载而加载,通过”类.静态方法”调用。只能调用静态的方法和属性;
注意点:static中this和super都不能用;
final
不能再被其他类所继承(修饰类的时候)
此方法不能再被重写(修饰方法时 )
变成常量,数据不能再被修改(修饰属性时)
一旦赋值,就只能再次方法中使用(修饰局部变脸时)
static final 用来修饰属性:全局常量
代码块
初始化类或者对象的
两种结构 static{} 或者{}(静态和非静态)
静态代码块:
内部可以有输出语句
随着类的加载而执行,而且只执行一次
权限比非静态的代码块高,优先执行
非静态代码块:
内部可以有输出语句
随着对象的加载而执行
每造一个对象都会执行一次
作用:可以在创建对象时,对对象的属性进行初始化
非静态顺序执行
接口 interface
全局常量:public static final
抽象方法: public abstract
除了定义全局常量和抽象方法之外,还可以定义静态方法,默认方法
不能定义构造器(所以不能实例化),通过让类去实现(implements)的方式来使用,如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类。
接口与接口之间是多继承的
匿名实现类
com.transferData()
异常处理
包含error和 exception两种,前者是java虚拟机无法解决的问题。后者是因程序错误或偶然的外在因素导致的
处理异常的方法
1 :try{可能出现异常的代码} - c atch(异常类型 变量名)(可以有多个catch)-finally{一定会执行的代码}
e.getMessage() 获取异常信息
e.printStackTrace() 显示错误信息
在try内声明的变量不能在外面使用;
处理异常时异常是编译时不再报错了,但是运行时可能报错,相当于将一个编译时的异常,延时到运行时了
2:throws+异常类型
在函数名后使用,他只是把异常抛给了方法的调用者。异常代码后续的代码,就不在执行了。并未把异常处理掉;
子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
3:如何自定义异常类
1,继承于现有的异常类:RuntimeException,Exception
2,提供全局常量:serialVersionUID(序列号)
3,提供重装的构造器
使用 therow new 异常类();
多线程
如何创建多线程
法1:继承于Thread类的子类;
1.创建一个继承于Thread类的子类;
2.重写Thread类人run()方法;
3.创建Thread类的子类的对象;
4.通过此对象调用start()方法;
public class ThreadTest extends Thread{
public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
threadTest.start();
System.out.println("hello word");
}
@Override
public void run() {
System.out.println("测试");
}
}
法2:实现Runable方法;
创建一个类实现Runable()接口
实体类去实现Runable中的抽象方法run();
创建实现类的对象
将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
通过Thread类的对象调用start();
package com.test; public class ThreadTest1 implements Runnable{ private int co =100; @Override public void run() { while (true){ if (co > 0){ System.out.println(Thread.currentThread().getName()+":"+co); co--; }else { break; } } } public static void main(String[] args) { ThreadTest1 threadTest1 = new ThreadTest1(); Thread t1 = new Thread(threadTest1); Thread t2 = new Thread(threadTest1); Thread t3 = new Thread(threadTest1); t1.start(); t2.start(); t3.start(); } }
两种方式那种好?
java是单继承所以使用实现的方式比较好,实现的方式更适合实现共享数据的情况,在开发中优先选择法2。
法3:实现Callable接口
1.相比run()方法,可以有返回值
2.方法可以抛出异常
3.支持泛型的返回值
4.需要借助FutureTask类,比如获取返回结果;
创建方法
1.创建一个实现Callable接口的类
2.实现call方法,将此线程需要执行的操作声明在call()方法中
3.创建callable实现类的对象
4.将此Callable接口是实现类的对象作为传递到FtureTask构造器中,创造FtureTaks的对象
5.将FutueTask的对象作为参数传递给Thread类的构造器中,创造Thread对象,并启用start();
class threadThest implements Callable {
@Override
public Object call() throws Exception {
int i=0;
System.out.println(".............\n"+(i++));
return i;
}
}
public class ThreadTest{
public static void main(String[] args) {
threadThest threadThest = new threadThest();
FutureTask futureTask = new FutureTask(threadThest);
Thread thread = new Thread(futureTask);
thread.start();
try {
Object sum = futureTask.get();
// System.out.println(sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
法4:线程池
/*
* 创建线程池
*
*
* */
class test implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"++++++++++-----------");
}
}
class test2 implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"++++++++++-----------");
}
}
public class ThreadCHI {
public static void main(String[] args) {
//提供指点数量的线程池
ExecutorService service = Executors.newFixedThreadPool(10);
//设置线程池的属性
ThreadPoolExecutor s1 = (ThreadPoolExecutor) service;
// s1.setCorePoolSize(15);//核心池的大小
// s1.setKeepAliveTime(10,TimeUnit.NANOSECONDS);//线程没有任务时做多会保持多长时间后悔终止
// s1.setMaximumPoolSize(3);//最大的线程数
//执行指定的线程操作。需要提供Runnable接口或者Callable接口的实现类的对象
test test = new test();
service.execute(test);//适合使用Runnable
service.execute(new test2());//适合使用Runnable
// service.submit(Callable callable);//适合使用Callable
service.shutdown();//关闭线程池
}
}
如何解决线程安全问题?
当一个线程操作共享数据的时候,其他线程不能参加进来。直到线程操作完成共享数据时,其他线程才能操作共享数据。这种情况即使线程出现了堵塞也不能被改变。
法1:同步代码块
synchronized(同步监视器){
需要被同步的代码(操作共享数据的代码,共享数据)
}
同步监视器:俗称锁(任何一个类的对象都可以作为一个锁,多个线程必须要公用同一把锁)
法二:同步方法
把方法声明成synchronized的类型(Thread继承中要设置成static)
法3:Lock锁(JDK5.0新增)
1.实例化一个ReetrantLock
2.将含有同步数据的代码放入try{
先调用lock()锁;
lock.lock();
}finally{
再解锁unlock();
lock.unlock();
}
synchrond 与 Lock的异同
相同:都可以解除线程安全;
不同:lock是手动的,synchronized是自动的;
Thread 中常用的方法
1.start()启动线程
2.run()通常需要重写此方法,将创建的线程要执行的操作声明放在此方法里
3.currentThread()静态方法,返回当前代码的线程
4.getName()获取当前线程的名字
5.setName()设置当前线程的名字
6.yield() 释放当线程的执行权(不一定会被别的线程所抢占)
7.join()在线程a中调用b的join方法,此时线程a进入阻塞状态,直到线程b完全执行以后,线程a才结束阻塞状态。
8.stop()强制结束生命周期(已过时)
9.sleep(long millitime)使线程进入休眠millitime毫秒。在指定的millitime毫秒时间内当前线程是阻塞状态;
线程的优先级
MAX_PRIORITY: 10
MIN_PRIORITY: 1
NORM_PRIORITY: 5
如何设置当前线程的优先级:(高优先级的线程要抢占低优先级线程的cpu,但是只是从概率上的,并不是一定会先执行)
getPriority():获取当前线程的优先级
setPriority() :设置当前线程优先级
死锁
不同的线程分别占用对方需要的资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。
出现死锁后,不会出现异常,不会出现提示,只是所有线程都处于阻塞状态,无法继续。
@Test
public void test3(){
StringBuffer st1 = new StringBuffer();
StringBuffer st2 = new StringBuffer();
new Thread(){
@Override
public void run() {
synchronized (st1) {
st1.append("a");
st2.append(1);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (st2) {
st1.append("b");
st2.append(2);
System.out.println(st1);
System.out.println(st2);
}
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (st2) {
st1.append("c");
st2.append(3);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (st1) {
st1.append("d");
st2.append(4);
System.out.println(st1);
System.out.println(st2);
}
}
}).start();
}
线程通信
线程如何交替打印:
先使用wait()使线程堵塞
notify()唤醒一个wait的线程
notifyAll()唤醒所有被wait的线程
上面三个方法必须要在同步代码块或者同步方法中,锁必须和同步监视器内的锁一样,这三方法定义在object中
sleep和wait的异同?
相同:一旦运行都会使线程进入阻塞状态
不同::
1.声明的位置不同 Thread类中声明sleep(),Object中声明wait();
2.调用的范围不同sleep在任何位置都可以,wait只能在同步监视器中
3.在使用同步代码块或同步方法时,sleep不会释放锁,wait会释放锁
线程的生命周期
String
String含义
1.使用一对””引起来表示
2.声明为final不可以被继承
3.实现了Serializable接口:表示字符串是支持序列化的
4.实现了Comparable接口:表示可以比较大小
5.内部定义了final char[] vale 用来存储字符串数据
6.代表不可变字符序列
7.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中
8.字符串常量池是闭环存储相 同内容的字符串的
String常用到的方法
String的转换
String转基本数据类型包装类:调用包装类的静态方法:parseXxx(str)
基本数据类型包装类转String:调用String重载的valueOf(xxx);
String与char[]的转换:调用String的toCharArray()
char[]转String:调用String的构造器
String转 byte[]:调用String的getBytes()
byte[]转String:调用String构造器 (要注意编码集是否一致)
StringBuffer和StringBuilder
String:不可变的字符序列
StringBuffer:可变的字符序列,线程安全的,效率低
StringBuilder:可变的字符序列,线程不安全的效率高点
常用的方法:
append():提供了很多的append()方法,用于进行字符串拼接
delete(int start,int end):删除指定位置的内容
replace(int start,int end,String str):把[start,end)位置替换成str
insert(int offset,xxx):在指定位置插入xxx
reverse():把当前字符序列逆转
时间api
java.text.SimpleDateFormat
:SimpleDateFormat对日期Data类的格式化解析
1.格式化(format()):将日期—–>字符串
2.解析(parse(String str) ):字符串(格式必须是:19-12-18 上午11:43)——>日期
使用
如何定义解析的字符串格式 在实例化的时候填参数即可
SimpleDateFormat sdf = new SimpleDateFormat(”日期格式”)
日期格式:
yyyy:年
MM:月
dd:日
hh:1~12小时制(1-12)
HH:24小时制(0-23)
mm:分
ss:秒
S:毫秒
E:星期几
D:一年中的第几天
F:一月中的第几个星期(会把这个月总共过的天数除以7)
w:一年中的第几个星期
W:一月中的第几星期(会根据实际情况来算)
a:上下午标识
k:和HH差不多,表示一天24小时制(1-24)。
K:和hh差不多,表示一天12小时制(0-11)。
z:表示时区
java.sql.Data 中如何使用
String sqlSt = "2022-12-12";
SimpleDateFormat sdf5 = new SimpleDateFormat("yyyy-MM-dd");
Date date3 = sdf5.parse(sqlSt);
java.sql.Date sqlData = new java.sql.Date(date3.getTime());
System.out.println(sqlSt);
Calendar日历
Calendar是抽象类不能实例化所以要获取它的子类,或方法
方法:
1.使用Calendar.getlnstance()方法
2.使用它的子类GregorianCalendar
常用方法
Calendar calendar = new Calendar;
1.get(特点格式)
格式 calendar.DAY_OF_MONTH(这只是其中一种)
2.set(特点格式,改动)
calendar.ser(特点格式,设置的信息)
3.add()
calendar.add(特点格式,添加几天);
4.getTime()
Data data = calendar.getTime();
5.setTime()
Data data = new Data();
calendar.setTime(data);
新的时间api(jdk8)
LocalData,LocalTime,LocalDataTime
instant(瞬时)
java.time.format.DateTimeFormatter
格式化或者解析日期,时间(类似于SimpleDateFormat)
实例化(三种方式)
1.预定于的标准格式:ISO_LOCAL_DATE_TIME;ISO_DATE;ISO_LOCAL_TIME
DateTimeFormatter isoLocalDateTime = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
//格式化 : 日期--》字符串
LocalDateTime now = LocalDateTime.now();
String format = isoLocalDateTime.format(now);
System.out.println(now);
System.out.println(format);
//解析 字符串--》日期
TemporalAccessor parse = isoLocalDateTime.parse("2022-09-06T19:42:32.5733531");
System.out.println(parse);
2.本地化相关的格式:ofLocalizedDateTime(FormatStyle.LONG)
//解析 字符串--》日期
TemporalAccessor parse = isoLocalDateTime.parse("2022-09-06T19:42:32.5733531");
System.out.println(parse);
System.out.println("-----------------------");
//FormatStyle.LONG / FormatStyle.MEDIUM /FormatStyle.SHORT :适用于LocalDateTime
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
//格式化
String format1 = dateTimeFormatter.format(now);
System.out.println(format1);
System.out.println("------------------");
//FormatStyle.LONG / FormatStyle.MEDIUM /FormatStyle.SHORT/FormatStyle :适用于LocalDate
DateTimeFormatter dateTimeFormatter1 =DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
String format2 = dateTimeFormatter1.format(LocalDate.now());
System.out.println(format2);
3.自定义格式:ofPattern(”yyyy-MM-dd hh:mm:ss E”)
System.out.println("-----------------------");
//格式化
DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
String format3 = dateTimeFormatter2.format(LocalDateTime.now());
System.out.println(format3);
//解析
TemporalAccessor parse1 = dateTimeFormatter2.parse("2022-09-06 03:52:09");
System.out.println(parse1);
java比较器
java中的对象正常情况下,只能进行比较:== 或!=。不能使用>或<,我们需要对多个对象进行排序,就需要比较对象的大小,使用两个接口中的任意一个:Comparable 或Comparator
Comparable (自然排序)
1.像String,包装类Comparable接口,重写了compareTo()方法,给出了比较两个大小的方式。
2.重写compareTo(obj)的规则:
如果当前对象this大于形参obj,则返回正数
如果当前对象this小于形参obj,则返回负数
如果当前对象this等于形参obj,则返回零
例:
package com.test;
import java.util.Comparator;
public class Goods implements Comparable {
private String name;
private double price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Goods(String name, int price) {
this.name = name;
this.price = price;
}
public Goods() {
}
@Override
public String toString() {
return "Goods{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
//指明排序规则
@Override
public int compareTo(Object o) {
if (o instanceof Goods){
//方式1
Goods goods = (Goods) o;
if (this.price> goods.price){
return 1;
}else if(this.price< goods.price){
return -1;
}else{
return 0;
}
//方式2 return Double.compare(this.price,goods.price);
}
throw new RuntimeException("传入数据类型异常");
}
@Test
public void test8(){
String[] st = new String[]{"aa","dd","bb","cc"};
Arrays.sort(st);
System.out.println(Arrays.toString(st));
System.out.println("-----------------");
Goods[] arr = new Goods[4];
arr[0] = new Goods("aaaa",12);
arr[1] = new Goods("bbbb",113);
arr[2] = new Goods("cccc",23);
arr[3] = new Goods("dddd",8);
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
Comparator(定制排序)
一旦指定,保证Comparable接口实现类的对象在任何位置都可以比较大小,Comparator接口属于临时性的比较
1.当元素没有实现Comparable 接口而又不方便修改代码。或者实现了Comparable 接口的排序不适合当前的操作,那么可以考虑使用Comparator的对象来排序
2.重写compare(Object o1,Object o2)方法,比较o1和o2的大小:
如果方法返回正整数,则表示o1大于o2
如果返回0,表示相等
如果返回负数,表示o1小于o2
例:
package com.test;
import java.util.Comparator;
public class Goods implements Comparable {
private String name;
private double price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Goods(String name, int price) {
this.name = name;
this.price = price;
}
public Goods() {
}
@Override
public String toString() {
return "Goods{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
//指明排序规则
@Override
public int compareTo(Object o) {
if (o instanceof Goods){
//方式1
Goods goods = (Goods) o;
if (this.price> goods.price){
return 1;
}else if(this.price< goods.price){
return -1;
}else{
return 0;
}
//方式2 return Double.compare(this.price,goods.price);
}
throw new RuntimeException("传入数据类型异常");
}
@Test
public void test8(){
System.out.println("-----------------");
String[] st = new String[]{"aa","dd","bb","cc"};
Arrays.sort(st, new Comparator(){
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof String && o2 instanceof String){
String s1 = (String) o1;
String s2 = (String) o2;
return -s1.compareTo(s2);
}
throw new RuntimeException("输入数据类型不一致");
}
});
System.out.println(Arrays.toString(st));
System.out.println("-----------------");
Goods[] arr = new Goods[5];
arr[0] = new Goods("aaaa",12);
arr[1] = new Goods("bbbb",113);
arr[2] = new Goods("cccc",23);
arr[3] = new Goods("dddd",8);
arr[4] = new Goods("cccc",21);
Arrays.sort(arr, new Comparator(){
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof Goods && o2 instanceof Goods){
Goods s1 = (Goods) o1;
Goods s2 = (Goods) o2;
if (s1.getName().equals(s2.getName())){
return -Double.compare(s1.getPrice(),s2.getPrice());
}else {
return -s1.getName().compareTo(s2.getName());
}
}
throw new RuntimeException("传入数据类型异常");
}
});
System.out.println(Arrays.toString(arr));
}
}
System类
native long currentTimeMillis():
返回当前的计算机时间,时间的格式为当前计算机时间和GMT(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数。
void exit(int status):
退出程序。其中staus的值为0代表正常退出,非零代表异常退出。
void gc():
请求系统进行垃圾回收。至于系统是否立刻回收,则取决于系统中垃圾回收算法的实现以及系统执行时的情况。
String getProperty(String key):
获得系统中属性名为key的属性对应的值。
![}G(I74I9E~}CV5G0D)}QX8](D:\A 两年计划学习目标\A.JavaSE\}G(I
74I9E~}CV5G0D)}QX8.png)
Math类
BigIntegert
BigDecimal
枚举类与注解
1.类的对象是有限个,确定的。
2.如果枚举类中只有一个对象,则可以作为单利模式的实现方法。
如何去定义枚举类
方式一:jdk5.0之前,自定义枚举类
//自定义枚举类
class Season{
// 声明Season对象的属性:private final 修饰
private final String seasonName;
private final String seasonDesc;
//私有化类的构造器,并给对象属性赋值
private Season(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
//提供枚举类的多个对象
public static final Season SPRING = new Season("春天","春暖花开");
public static final Season SUMMER = new Season("夏天","春暖花开");
public static final Season AUTUMN = new Season("秋天","春暖花开");
public static final Season WINTER = new Season("冬天","春暖花开");
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
@Override
public String toString() {
return "Season{" +
"seasonName='" + seasonName + '\'' +
", seasonDesc='" + seasonDesc + '\'' +
'}';
}
}
方式二:jdk5.0,可以使用enum关键字定义枚举类
//使用enum定义类(定义的枚举类默认继承enum)
enum Season1{
//1.提供当前枚举类的对象,多个对象之间用,隔开,末尾用;结束
//提供枚举类的多个对象
SPRING("春天","春暖花开"),
SUMMER("夏天","春暖花开"),
AUTUMN("秋天","春暖花开"),
WINTER("冬天","春暖花开");
private final String seasonName;
private final String seasonDesc;
//私有化类的构造器,并给对象属性赋值
private Season1(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
}
Enum类的主要方法
valus()方法:返回枚举类类型的对象数组。该方法可以提供很方便地遍历所有枚举类。
valueOf(String str):可以把一个字符串转换成对应的枚举类对象。要求字符串必须是枚举类对象的”名字”。如果不是,会有运行时异常:IIIegalArgumentException
toString():返回当前枚举类对象常量名
接口类在枚举类中的应用
1.正常情况与之前正常接口类的使用方法是一样的
2.在枚举类中,对于当前的枚举类对象,实现接口可以直接在枚举类的对象后加{重写方法}来实现不同枚举类对象显示方法
例:
interface testImp{
public void show();
}
//使用enum定义类(定义的枚举类默认继承enum)
enum Season1 implements testImp{
//1.提供当前枚举类的对象,多个对象之间用,隔开,末尾用;结束
//提供枚举类的多个对象
SPRING("春天","春暖花开"){
@Override
public void show() {
System.out.println("这是春天");
}
},
SUMMER("夏天","春暖花开"){
@Override
public void show() {
System.out.println("这是夏天");
}
},
AUTUMN("秋天","春暖花开"){
@Override
public void show() {
System.out.println("这是秋天");
}
},
WINTER("冬天","春暖花开"){
@Override
public void show() {
System.out.println("这是冬天");
}
};
private final String seasonName;
private final String seasonDesc;
//私有化类的构造器,并给对象属性赋值
private Season1(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
}
注解
JDK内置的三个基本注解
@Override:限定重写父类方法,该注解只能用于方法
@Deprecated:用于表示所修饰的元素(类,方法等)已过时的。通常是因为所修饰的结构危险或存在更好的选择
@SuppressWarnings:一直编译器警告
如何自定义注解?
参照@SuppressWarnings去定义即可
1.注解声明为@interface
2.内部定义成员,通常使用value表示
3.可以指定成员的默认值,使用default定义
4.如果自定义注解没有成员,表面是一个标记
如果注解有成员变量,在使用注解时,需要指明成员的值。
自定义注解必须配上注解的信息处理流程(使用反射)才有意义。
自定义注解通过都会指明两个源注解:Retention,Target
jdk中的元注解
提供四个标准的meta-annotation类型分别为:
1.Retention
指定所修饰的Annotation的生命周期:SOURCE\CLASS(默认行为)\RUNTIME只有声明为RUNTIME声明周期的注解才能被反射获取
2.Target
用于指定被修饰的Annotation能用于修饰那些程序元素
![`S_5GK$F{0M}S4CM526TE)Y](D:\A 两年计划学习目标\A.JavaSE\23323.png)
下面两个频率出现的低基本不怎么出现*
3.Documented(定义此注解必须设置Retention值为RUNTIME)
用于指定被该元Annotation修饰的Annotation类将被javadoc工具提起成文档。默认情况下,javadoc是不包括注解的
4.Inherited
5.通过反射获取注解信息
6.Repeatable
可重复注解,在MyAnnotation上声明@Repeatable,成员值为MyAnnotations.class,在MyAnnotation的Target和Retention和MyAnnotions相同
7.类型注解
java集合框架
1.集合,数值都是对多个数据进行存储操作的结构,简称java容器。(此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt,.jpg,.avi 等等))
2.数组在存储多个数据方面的特点:
一旦初始化长度是确定的
数组一旦定义好,其元素的类型也确定了,我们只能操作指定类型的数据了
3.数组在存储多个数据方面的缺点:
一旦初始化以后,其长度不可修改
数组中提供的方法有限,集合提供增删改查方法
获取数组中实际元素个数的需求,数组没有现成的属性或者方法可用
数组存储数据的特点:有序,可重复。对于无序,不可重复的需求,不能满足
java集合分为两个体系:Collection和Map
Collection接口
单列数据,定义了存储一组对象的方法的集合
List:元素有序,可重复的集合(ArrayList(list的主要实现类,线程不安全的,效率高,底层使用object[]存储),LinkedList(对于频繁插入,删除操作,次类比ArrayList效率高,底层双向链表存储),Vector(古老实现类))
特有的方法:
Set:元素无序,不可重复的集合(HashSet(主要实现类,线程不安全,可以存储null),LinkedHashSet(HashSet的子类;便利内部数据时,可以按照添加的顺序遍历),TreeSet(添加元素必须是同一个类,可以按照添加对象的指定属性,进行排序 ))
无序性:不等于随机性,存储的数据在底层数组中并非按照数组索引添加,而是根据数据的哈希值添加
不可重复性:保证添加的元素按照equals()判断时,不能返回true,即:相同的元素只能添加一个
Collection接口包含的方法:
add(object e):添加元素e添加到集合中
size():获取添加元素的个数
addAll(Collection c):添加c集合到集合中
isEmpty():判断当前集合是否为空
clear():清空集合
contains(Object obj):判断当前集合中是否包含obj(判断会调用obj对象所在类的equals()方法)
containsAll(Collection c):判断c的所有元素是否在集合中
remove(object o):从当前集合中删除o元素
removeAll(Collection c):移除当前集合中c中的所有元素(求差集)
retainAll(Collection c):将当前集合中和c中集合相同的元素放入集合(求交集)
equals(object obj) : obj是否和当前集合元素相同
hashCode():返回当前对象的哈希值
toArray(): 集合转换成数组
Arrays.asList(T t):数组转换成集合
iterator():返回Iterator接口的实例,用于遍历集合元素(迭代器接口)
next():指针下移,将下以后的集合位置上的元素返回
hasNext() :判断当前集合是否还有下一个元素
remov():移除当前元素
Map接口
双列数据,保存具有映射关系”key-value对”的集合
Map中的key:无序的,不可重复的,使用Set存储所有的key(key所在的类要重写equals()和hashCode()方法:以HashMap为例)
Map中value:无序的,可重复的,使用Collection存储所以的value(value所在的类要重写equals())
一个键值对:key-value构成一个Entry对象
Map中的entry:无序的,不可重复的,使用Set存储所有的entry
HashMap(主要实现类,线程不安全,效率高,存储null的key和value)
LinkedHashMap(保证在遍历map元素时,可以按照添加的顺序实现遍历)
TreeMap(保证按照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序和定制排序,底层使用红黑数)
Hashtable(古老实现类,线程安全,效率低,不能存储null的key和value)
Properties(常用来处理配置文件。key和value都是String)
底层代码:
jdk7
HashMap map = new HashMap( ):
在实例化以后,底层创建了长度是16的一维数组Entry[] table….可能已经执行过多次put. . .
map.put(key1, vaLue1):
首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算以后,得到Entry数组中的存放位置,如果此位置上的数据为空,此时的key1-value1添加成功。—-情况1
如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表形式存在)),比较key1和已存在的一个或多个三个月后又的哈希值:
如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功。—-情况二
如果key1的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同,继续比较:调用key1所在类的equals(key2)
如果equals()返回faLse:此时key1-value1添加成功。—-情况3
如果equals()返回true:使用value1替换value2 。
补充:关于情况2和情况3:此时key1-value1和原来的数据以链表的方式存储。
在不断的添加过程中,会涉及到扩容问题,默认的扩容方式:扩容为原来容量的2倍,HashMap 的容量是有上限的,必须小于 1<<30,即 1073741824。如果容量超出了这个数,则不再增长,且阈值会被设置为 Integer.MAX_VALUE。
jdk8相较于jdk7在底层实现方面的不同:
- new HashMap():底层没有创建一个长度为16的数组
- jdk 8底层的数组是:Node[],而非Entry[ ]
- 首次调用put()方法时,底层创建长度为16的数组
- jdk7底层结构只有:数组+链表。jdk8中底层结构:数组+链表+红黑树。当数组的某一个索引位置上的元素以链表形式存在的数据个数>8且当前数组的长度〉64 此时此索引位置上的所有数据改为使用红黑树存储。
- DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16
- DEFAULT_LOAD_FACTOR: HashMap的默认加载因子:0.75
- threshold:扩容的临界值,=容量填充因子:160 * 0.75 => 12
- TREETEY_THRESHOLD: Bucket中链表长度大于该默认值,转化为红黑树:8
- MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量:64
实现类:
添加、删除、修改操作:
Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
void putAll(Map m):将m中的所有key-value对存放到当前map中
Object remove(Object key):移除指定key的key-value对,并返回value
void clear():清空当前map中的所有数据
putIfAbsent() :方法会先判断指定的键(key)是否存在,不存在则将键/值对插入到 HashMap 中
元素查询的操作:
Object get(Object key):获取指定key对应的value
boolean containsKey(Object key):是否包含指定的key
boolean containsValue(Object value):是否包含指定的value
int size():返回map中key-value对的个数
boolean isEmpty():判断当前map是否为空
boolean equals(Object obj):判断当前map和参数对象obj是否相等
元视图操作的方法:
Set keySet():返回所有key构成的Set集合
Collection values():返回所有value构成的Collection集合Set
entrySet():返回所有key-value对构成的Set集合
Collections工具类
Collections是一个操作Set、List和l Map 等集合的工具类
Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法
排序操作:(均为static方法)
reverse(List):反转List中元素的顺序
shuffle(List):对List集合元素进行随机排序
sort(List):根据元素的自然顺序对指定List集合元素按升序排序
sort(List,Comparator):根据指定的Comparator 产生的顺序对List集合元素进行排序
swap(List,int,int):将指定list集合中的i处元素和j处元素进行交换
查找、替换
Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
Object max(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素
Object min(Collection)
Object min(Collection,Comparator)
int frequency(Collection,Object):返回指定集合中指定元素的出现次数
void copy(List dest,List src):将src中的内容复制到dest中(List dest = Arrays.asList(new Object[src.size])创建dest的正确方法)
boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换List对象的所有旧值
Collections类中提供了多个synchronizedXxx()方法
该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题
foreach增强for循环
for(元素的类型 局部变量:对象)
泛型
所谓泛型,就是允许在定义类、接口时通过个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时(例如继承或实现这个接口,用这个类型声明变量创建对象时)确定(即传入实际的类型参数,也称为类型实参)
在集合中使用泛型
1,集合接口或者集合类在jdk5.0时都修改为泛型的结构
2,在实例化集合类时,可以指明具体的泛型类型
3,指明完以后,在集合类或接口中凡是定义类或者接口时,内部结构使用到类的泛型的位置,都指定为实例化时的泛型类型(例:add(E e)—–> add( Integer e))
4,泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换。
5,如果实例化时没有指明泛型,默认类型为Object类型
泛型注意点
静态方法中不能使用类泛型(静态方法调用先于泛型)
异常类不能使用泛型
泛型方法
在方法中出现的泛型的结构,泛型参数与类的泛型参数没有任何关系,换句话说,在泛型方法所属的类是不是泛型类都没关系。
泛型方法可用声明为静态的(泛型参数是在调用方法时确定的,并非在实例化类时确定)
例:public
泛型在继承方面的体现
类A是类B的父类或者接口,A
通配符 ( ?)
类A是类B的父类,G和G是没有关系的,二者共同的父类是:G<?>
1.对于List<?>就不能向其内部添加数据,除了null;
2.允许读取(get)数据,读取类型为Object
有限制条件的调配符
? extends A(类名)【小于等于】
G<? extends A> 可以作为G和G的父类,其中B是A的子类
?super A(类名)【大于等于】
G<? extends A> 可以作为G和G的父类,其中B是A的父类
File类
文件和文件目录路劲的抽象表达形式,与平台无关
File 能新建、删除、重命名文件和目录,但 File不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。
想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File对象,但是Java程序中的一个File对象,可能没有一个真实存在的文件或目录
File对象可以作为参数传递给流的构造器
File类中涉及到关于文件或文件目录的创建,删除,重命名,修改时间,文件大小等方法,并未涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO流来完成
如何创建File类的实例
public File(String pathname)
以pathname为路径创建File对象,可以是绝对路径或者相对路径,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。
绝对路径:是一个固定的路径,从盘符开始
相对路径:是相对于某个位置开始
public File(String parent,String child)
以parent为父路径,child为子路径创建File对象。
public File(File parent,String child)
根据一个父File对象和子文件路径创建File对象
路径分隔符:windos:\ unix: /
获取方法:
public String getAbsolutePath():
获取绝对路径oublic String getPath():获取路径
oublic String getName():
获取名称
public String getParent():
获取上层文件目录路径。若无,返回null
public long length():
获取文件长度(即:字节数)。不能获取目录的长度。
public long lastModified():
获取最后一次的修改时间,毫秒值
public String[] list():
获取指定目录下的所有文件或者文件目录的名称数组
public File[] listFiles():
获取指定目录下的所有文件或者文件目录的File数组
public boolean renameTo(File dest):
把文件重命名为指定的文件路径
例:file1.renameTo(file2)想要返回true吗,需要file1在硬板中是存在的,且file2不能在硬盘中存在
判断方法
public boolean isDirectory():
判断是否是文件目录
public boolean isFile():
判断是否是文件
public boolean exists() :
判断是否存在
public boolean canRead() :
判断是否可读
public boolean canWrite():
判断是否可写
public boolean isHidden():
判断是否隐藏
创建方法
public boolean createNewFile():
创建文件。若文件存在,则不创建,返回false
public boolean mkdir():
创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。
public boolean mkdirs():
创建文件目录。如果上层文件目录不存在,一并创建
注意事项:如果你创建文件或者文件目录没有写盘符路径,那么,默认在项目径下。
删除方法
public boolean delete():
删除文件或者文件夹删除注意事项:Java中的删除不走回收站。要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录
IO流
流的分类
1.操作数据单位:字节流,字符流
2.数据的流向:输入流,输出流
3.流的角色:节点流,处理流
流的体系结构
读入文件
read()返回读入的一个字符。如果达到文件末尾返回-1;
异常的处理:为了保证流资源一定可以执行关闭操作。需要用try-catch-finally处理
读入的文件一定要存在,否则会报FileNoteFoundException
对read()操作升级:使用read的重载方法
read(char[] cbuf):返回每次读入cbuf数组中的字符个数,如果达到文件末尾返回-1
从内存中写出数据到硬盘文件
写出文件不存在,会自动帮你创建
写出是覆盖不是添加(FileWriter(file))
写出添加(FileWriter(file,true))(是false的时候是覆盖)
图片的复制
不能使用字符流来处理图片,需要使用字节流来实现
1.对于文本文件使用(.txt .java .c .cpp),字符流来处理
2.对于非文本文件(.jpg .mp3 .mp4 .avi .doc),使用字节流来处理
缓冲流(提高流的读取,写入速度)
关闭时要先关外层流再关内层流(关闭外层流的同时,内层流自动关闭。所以内层流的关闭可以省略)
提高读写速度的原因:内部提高了一个缓冲区
flush()刷新缓冲区
处理流就是套接在已有的流的基础上的
readLine():null读完数据,读取一行数据
newLine():提供换行操作
处理流之二:转换流的使用
1:转换流:
InputStreamReader
将一个字节的输入流转换为字符的输入流
OutputStreamWriter
将一个字符的输出流转换成字节的输入流
2.作用:提供字节流与字符流之间的转换
3.解码:字节,字节数组 —> 字符数组,字符串
4.编码:字符数组,字符串—->字节,字节数组
5.字符集:
ASCII:美国标准信息交换码。用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表。用一个字节的8位表示。
GB2312:中国的中文编码表。最多两个字节编码所有字符
GBK:中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节编码
Unicode:国际标准码,融合了目前人类使用的所有字符。为每个字符分配唯一的字符码。所有的文字都用两个字节表示
UTF-8:变长的编码方式,可用1-4个字节来表示一个字符。
输入输出流:
1.System.in:标准的输入流,默认从键盘输入
2.System.sou:标准的输出流,默认从控制台输出
3.System类的setIn(InputStream is)/setOut(PrintStream ps)方式重新指定输入和输出的流
例:
package com.test;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @author Alitar
* @date 2022-09-26 21:31
*/
public class SystemTest{
// System.in ---> 转换流 ---> BufferedWriter( readLine())
public static void main(String[] args) {
BufferedReader bufferedReader = null;
try {
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
bufferedReader = new BufferedReader(inputStreamReader);
while (true){
System.out.println("请输入字符串:");
String data = bufferedReader.readLine();
// equalsIgnoreCase()忽略大小写判断
if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)){
System.out.println("程序退出!");
break;
}
// toUpperCase()将字符串转换为大写
System.out.println(data.toUpperCase());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bufferedReader != null)
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
打印流
1.实现将基本数据类型的数据格式转化为字符串输出
2.打印流: PrintStream和PrintWriter
提供了一系列重载的print()和println()方法,用于多种数据类型的输出
3.PrintStream和PrintWriter的输出不会抛出IOException异常
4.PrintStream和PrintWriter有自动flush功能
5.PrintStream打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字符而不是写入字节的情况下,应该使用PrintWriter类。
6.System.out返回的是PrintStream的实例
例:
@Test
public void test1(){
PrintStream printStream = null;
try {
// 创建打印输出流,设置为自动刷新模式(写入换行符或者”\n”时会刷新缓冲区)
printStream = new PrintStream(new FileOutputStream(new File("D:\\cll\\test\\test.txt")),true);
if (printStream != null){//把标准输出流 改成文件
System.setOut(printStream);
}
for (int i=0;i<=255;i++) {//输出ASCII字符
System.out.print(((char) i));
if (i%50 == 0){
System.out.println();//换行
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (printStream != null)
printStream.close();
}
}
数据流
1.为了方便地操作Java语言的基木数据类型和String的数据,可以使用数据流。数据流有两个类:(用于读取和写出基本数据类型、String类的数据)
2.DatalnputStream和 DataOutputStream
3.分别“套接”在InputStream和 OutputStream子类的流上
4.Datalnputstream中的巧法
boolean readBoolean()
byte readByte()
char readChar()
float readFloat()
double readDouble()
short readShort()
long readLong()
int readInt()
String readUTF()
void readFully(byte[] b)
5.DataOutputStream中的方法
将上述的方法的read改为相应的write即可。
6.作用:用于读取或写出基本数据类型的变量或者字符串
例:
@Test
public void test2(){
//将基本数据类型写入到文件中
DataOutputStream dataOutputStream = null;
try {
dataOutputStream = new DataOutputStream(new FileOutputStream("add.txt"));
dataOutputStream.writeUTF("蔡徐坤");
dataOutputStream.flush();
dataOutputStream.writeInt(32);
dataOutputStream.flush();
dataOutputStream.writeBoolean(true);
dataOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (dataOutputStream != null) {
try {
dataOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void test3(){
// 将文件中存储的基本数据类型变量和字符串读取到内存中,保存在变量里
// 注意读取不同类型的数据要与当初写入的文件时,保存的数据顺序一致
DataInputStream dataInputStream = null;
try {
dataInputStream = new DataInputStream(new FileInputStream("add.txt"));
String s = dataInputStream.readUTF();
int i = dataInputStream.readInt();
boolean b = dataInputStream.readBoolean();
System.out.println("name = " + s + "age =" + i + "男?" + b);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (dataInputStream != null)
dataInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
对象流
ObjectlnputStream和OjbectOutputSteam
用于存储和读取基木数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。
序列化:用ObjectOutputStream类保存基本类型数据或对象的机制
反序列化:用ObjectlnputStream类读取基本类型数据或对象的机制
ObjectOutputStream和ObjectInputStream不能序列化static和ltransient修饰的成员变量对象序列化机制
1.序列化
允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。(当其它程序获取了这种二进制流,就可以恢复成原来的Java对象)
序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据,使其在保存和传输时可被还原序列化是 RMI (Remote Method Invoke-远程方法调用)过程的参数和返回值都必须实现的机制,而RMI是JavaEE的基础。因此序列化机制是JavaEE平台的基础
如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一。否则,会抛出NotSerializableException异常
自定义类的时候需要实现下面两个接口 的任一,除了当前类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。(默认情况下,基本数据类型可序列化)
注意:static和transient修饰的成员变量不能序列化
Serializable
凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:
private static final long serialVersionUID;
serialVersionUID用来表明类的不同版本间的兼容性。简言之,其目的是以序列化对象进行版本控制,有关各版本反序列化时是否兼容。
如果类没有显示定义这个静态常量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID可能发生变化。故建议,显式声明。
简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的
serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException)
Externalizable
2.序列化过程
将java对象保存到磁盘中或通过网络传输出去
例:
@Test
public void test1(){
ObjectOutputStream objectOutputStream = null;
try {
objectOutputStream = new ObjectOutputStream(new FileOutputStream("object.txt"));
objectOutputStream.writeObject(new String("你是傻逼?"));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (objectOutputStream != null) {
try {
objectOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3.反序列化过程
将磁盘文件中的对象还原为内存中的一个java对象
例:
@Test
public void test2(){
ObjectInputStream objectInputStream = null;
try {
objectInputStream = new ObjectInputStream(new FileInputStream("object.txt"));
Object o = objectInputStream.readObject();
String st = (String) o;
System.out.println(st);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (objectInputStream != null) {
try {
objectInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
随机存取文件流
1.RandomAccessFile声明在java.io包下,但直接继承于java.lang.Object类。并且它实现了Datalnput、DataOutput这两个接口,也就意味着这个类既可以读也可以写。
2.RandomAccessFile类支持“随机访问”的方式,程序可以直接跳到文件的任意地方来读、写文件
支持只访问文件的部分内容
可以向已存在的文件后追加内
3.RandomAccessFile对象包含一个记录指针,用以标示当前读写处的位置
4.RandomAccessFile类对象可以自由移动记录指针:
long getFilePointer():获取文件记录指针的当前位置
void seek(long pos):将文件记录指针定位到pos位置
5.构造器
如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)
public RandomAccessFile(File file, String mode)
public RandomAccessFile(String name, String mode)
创建RandomAccessFile类实例需要指定一个mode参数,该参数指定RandomAccessFile的访问模式:
r:以只读方式打开
rw:打开以便读取和写入
rwd:打开以便读取和写入;同步文件内容的更新
rws:打卉以便读取和写入;同步文件内容和元数据的更新
如果模式为只读r。则不会创建文件,而是会去读取一个已经存在的文件,如果读取的文件不存在则会出现异常。如果模式为rw读写。如果文件不存在则会去创建文件,如果存在则不会创建。
Java NlIO
(New lO,Non-Blocking lO)是从Java 1.4版本开始引入的一套新的IOAPI,可以替代标准的Java lO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的(IO是面向流的)、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。
1.JavaAPI中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。
|—–java.nio.channels.Channel
|—–FileChannel:处理本地文件
l—–SocketChannel:TCP网络编程的客户端的Channel
|—–ServerSocketChannel:TCP网络编程的服务器端的Channel
|—–DatagramChannel:UDP网络编程中发送端和接收端的Channel
2.Path、Paths、Files类的使用
早期的Java只提供了一个File类来访问文件系统,但File类的功能比较有限,所提供的方法性能也不高r 而且,大多数方法在出错时仅返回失败,并不会提供异常信息。
NIO.2为了弥补这种不足,引入了Path接口,代表一个平台无关的平台路径,描述了目录结构中文件的位置。Path可以看成是File类的升级版本,实际引用的资源也可以不存在。
在以前IO操作都是这样写的:
import java.io.File;
File file = new File(“index.html”);
但在Java7中,我们可以这样写:
import java.nio.file.Path;
import java.nio.file.Paths;
Path path = Paths.get(“index.html”);
同时,NIO.2在java.nio.file包下还提供了Files、Paths工具类,Files包含了大量静态的工具方法来操作文件;Paths则包含了两个返回Path的静态工厂方法。
Paths类提供的静态get()方法用来获取Path对象:
static Path get(String first, String … more):用于将多个字符串串连成路径
static Path get(URl uri):返回指定uri对应的Path路径
3.Path 常用方法:
String toString():返回调用Path 对象的字符串表示形式
boolean startsWith(String path):判断是否以path 路径开始
boolean endsWith(String path):判断是否以path路径结束
boolean isAbsolute():判断是否是绝对路径
Path getParent():返回Path对象包含整个路径,不包含Path对象指定的文件路径
Path getRoot():返回调用Path 对象的根路径
Path getFileName():返回与调用Path 对象关联的文件名
int getNameCount():返回Path 根目录后面元素的数量
Path getName(int idx):返回指定索引位置idx 的路径名称
Path toAbsolutePath():作为绝对路径返回调用Path 对象
Path resolve(Path p):合并两个路径,返回合并后的路径对应的Path对象
File toFile():将Path转化为File类的对象
4.java.nio.file.Files
用于操作文件或目录的工具类。Files常用方法:
Path copy(Path src,Path dest, CopyOption … how):文件的复制
Path createDirectory(Path path, FileAttribute<?> … attr):创建一个目录
Path createFile(Path path, FileAttribute<?> … arr):创建一个文件
void delete(Path path)︰删除一个文件/目录,如果不存在,执行报错
void deletelfExists(Path path): Path对应的文件/目录如果存在,执行删除
Path move(Path src,Path dest, CopyOption…how):将src移动到dest位置
long size(Path path):返回path指定文件的大小
网络编程
IP
IP地址:InetAddress
唯一的标识Internet上的计算机(通信实体)
本地回环地址(hostAddress):127.0.0.1 主机名(hostName): localhost>IP地址分类方式1:IPV4和 IPV6
IPV4:4个字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。2011年初已经用尽。以点分十进制表示,如192.168.0.1
IPV6: 128位(16个字节),写成8个无符号整数,每个整数用四个十六进制位表示,数之间用冒号(:)分开,如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984
IP地址分类方式2:公网地址(万维网使用)和私有地址(局域网使用)。192.168.开头的就是私有址址,范围即为192.168.0.0–192.168.255.255,专门为组织机构内部使用
特点:不易记忆
如何实例化InetAddress:
getByName(String host) :获取host的ip
getLocalHost():获取本机ip
getHostName():获取域名
getHostAddress():获取主机地址ip
端口号
端口号标识正在计算机上运行的进程(程序)
不同的进程有不同的端口号
被规定为一个16位的整数0~65535。
端口分类:
公认端口:O~1023。被预先定义的服务通信占用(如:HTTP占用端口
80,FTP占用端口21,Telnet占用端口23)注册端口:1024~49151。分配给用户进程或应用程序。(如: Tomcat占
用端口8080,MySQL占用端口3306,Oracle占用端口1521等)。动态/私有端口:49152~65535。
端口号与IP地址的组合得出一个网络套接字:Socket
网络协议
TCPIP势议簇
●传输层协议中有两个非常重要的协议:
传输控制协议TCP(Transmission Control Protocol)
用户数据报协议UDP(User Datagram Protocol)。
●TCP/IP以其两个主要协议:传输控制协议(TCP)和网络互联协议(IP)而得名,实际上是一组协议,包括多个具有不同功能且互为关联的协议。
●lP(Internet Protocol)协议是网络层的主要协议,支持网间互连的数据通信
●TCP/IP协议模型从更实用的角度出发,形成了高效的四层体系结构,即物理链路层、IP层、传输层和应用层。
TCP协议:
使用TCP协议前,须先建立TCP连接,形成传输数据通道
传输前,采用“三次握手”方式,点对点通信,是可靠的
TCP协议进行通信的两个应用进程:客户端、服务端。
在连接中可进行大数据量的传输
传输完毕,需释放已建立的连接,效率低
UDP协议:
将数据、源、目的封装成数据包,不需要建立连接
每个数据报的大小限制在64K内
发送不管对方是否准备好,接收方收到也不确认,故是不可靠的
可以广播发送
发送数据结束时无需释放资源,开销小,速度快
TCP例:
package test;
import org.junit.Test;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author Alitar
* @date 2022-10-03 21:52
*
*/
//客户端
public class socketTest {
@Test
public void test1(){
Socket socket = null;
OutputStream outputStream = null;
try {
// 创建socket对象,指明服务器的ip和端口号
InetAddress inet = InetAddress.getByName("127.0.0.1");
socket = new Socket(inet, 8898);
// 获取一个输出流,用于输出
outputStream = socket.getOutputStream();
// 写出数据
outputStream.write("你好我是".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (outputStream != null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void test2(){
ServerSocket serverSocket = null;
Socket socket = null;
ByteArrayOutputStream byteArraOututStream = null;
InputStream inputStream=null;
try {
// 指明自己的端口号
serverSocket = new ServerSocket(8898);
// 接收来自客户端的socket
socket= serverSocket.accept();
inputStream = socket.getInputStream();
// 读入输入流的数据
byteArraOututStream = new ByteArrayOutputStream();
byte[] bytes = new byte[5];
int len = 0;
while ((len = inputStream.read(bytes)) != -1){
byteArraOututStream.write(bytes,0,len);
}
System.out.println(byteArraOututStream.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (byteArraOututStream != null){
try {
byteArraOututStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream != null){
try {
byteArraOututStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (serverSocket != null){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
TCP文件传输例:
package test;
import org.junit.Test;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author Alitar
* @date 2022-10-04 19:11
*/
public class TCPTest {
@Test
public void test1() {
Socket socket = null;
OutputStream outputStream = null;
BufferedInputStream bufferedInputStream = null;
ByteArrayOutputStream byteArrayOutputStream = null;
try {
InetAddress inet = InetAddress.getByName("127.0.0.1");
socket = new Socket(inet, 8889);
outputStream = socket.getOutputStream();
bufferedInputStream = new BufferedInputStream(new FileInputStream(new File("00c38545f55d4e8e938de19d0be0b073_2.jpeg")));
int len;
byte[] bytes = new byte[1024];
while ((len = bufferedInputStream.read(bytes))!=-1){
// byteArrayOutputStream.write(bytes,0,len);
outputStream.write(bytes,0,len);
}
socket.shutdownOutput();
InputStream inputStream = socket.getInputStream();
byteArrayOutputStream = new ByteArrayOutputStream();
int len1;
byte[] bytes1 = new byte[5];
while ((len1 = inputStream.read(bytes1))!=-1){
byteArrayOutputStream.write(bytes1,0,len1);
}
System.out.println(byteArrayOutputStream.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream!= null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedInputStream!=null){
try {
bufferedInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (byteArrayOutputStream!=null){
try {
byteArrayOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void test2() {
ServerSocket serverSocket = null;
InputStream inputStream = null;
BufferedOutputStream bufferedWriter = null;
try {
serverSocket = new ServerSocket(8889);
Socket accept = serverSocket.accept();
inputStream = accept.getInputStream();
bufferedWriter = new BufferedOutputStream(new FileOutputStream(new File("tcp1.jpeg")));
//ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int len;
byte[] bytes = new byte[1024];
while ((len = inputStream.read(bytes)) != -1){
// byteArrayOutputStream.write(bytes,0,len);
bufferedWriter.write(bytes,0,len);
}
OutputStream outputStream = accept.getOutputStream();
outputStream.write("你好美女已经接收到图片了!".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally{
if (serverSocket != null){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream!= null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedWriter!=null){
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
UDP的网络编程
package test;
import org.junit.Test;
import java.io.IOException;
import java.net.*;
/**
* @author Alitar
* @date 2022-10-04 20:18
*/
public class UDPTest {
// 发送段
@Test
public void test1(){
DatagramSocket datagramSocket = null;
try {
datagramSocket = new DatagramSocket();
String st= "你好我是你爸爸";
byte[] bytes = st.getBytes();
InetAddress localHost = InetAddress.getLocalHost();
DatagramPacket datagramPacket = new DatagramPacket(bytes,0,bytes.length,localHost,8595);
datagramSocket.send(datagramPacket);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (datagramSocket!= null){
datagramSocket.close();
}
}
}
@Test
public void test2(){
DatagramSocket datagramSocket = null;
try {
datagramSocket = new DatagramSocket(8595);
byte[] bytes = new byte[100];
int len;
DatagramPacket datagramPacket = new DatagramPacket(bytes,0,bytes.length);
datagramSocket.receive(datagramPacket);
System.out.println(new String(datagramPacket.getData(),0,datagramPacket.getLength()));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (datagramSocket!=null){
datagramSocket.close();
}
}
}
}
URL网络编程:
URL(Uniform Resource Locator):统一资源定位符,它表示Internet上某资源的地址。
它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。
通过URL我们可以访问Internet上的各种网络资源,比如最常见的 www,ftp站点。浏览器通过解析给定的URL可以在网络上查找相应的文件或其他资源。URL的基本结构由5部分组成:
<传输协议>:/<主机名>:<端口号>小<文件名>#片段名?参数列表>
例如:
http:l192.168.1.100:8080/helloworld/index.jsp#a?username=shkstart&password=123≥片段名:即铺点,例如看小说,直接定位到章节
参数列表格式:参数名=参数值&参数名=参数值….
常用方法
一个URL对象生成后,其属性是不能被改变的,但可以通过它给定的方法来获取这些属性:
public String getProtocol()获取该URL的协议名
public String getHost( ) 获取该URL的主机名
public String getPort( ) 获取该URL的端口号
public String getPath( ) 获取该URL的文件路径
public String getFile( ) 获取该URL的文件名
public String getQuery( ) 获取该URL的查询名
反射
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作狂意对象的内部属性及方法。
加载完类之后,在堆内存的方法区中就产生了一个class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。
正常方式:引入需要的”包类”名称—->
通过new实例化 ——> 取得实例化对象
反射方式:实例化对象——->getClass()方法———>得到完整的“包类”名称
动态语言
是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。
主要动态语言:Object-C、C#、JavaSeript、PHP、Python、Erlang。
静态语言
与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java、c、C++。
Java反射机制提供的功能
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时获取泛型信息
在运行时调用任意一个对象的成员变量和方法
在运行时处理注解
生成动态代理
相关api
java.lang.Class:代表一个类
1.类的加载过程:
程序经过javac.exe命令以后,会生成一个或多个字节码文件(.cLass结尾)。
接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为cLass亚一个实例。
获取Class的实例的方法:
方式一:调用运行时类的属性:.class
Class clazz = new 类名.class;
方式二:通过运行时的对象,调用getClass()
类名 p = new 类名();
Class clazz = p.getClass()
方式三:调用Class的静态方法:forName(String classPath)
Class clazz = Class.forName(”类的位置”);//例com.exa.类型
方式四:使用类的加载器:ClassLoader
ClassLoader classLoader = 类名.class.getClassLoader();
Class clazz = classLoader .loadClass(”类的位置”)
2.换句话说,class的实例就对应着一个运行时类。
3.加载到内存中的运行时的类,会缓存一定的时间。再次时间之内,我们可以通过不同的方式获取此运行时类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造器
…….
读取配置文件:
例:
package test;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* @author Alitar
* @date 2022-10-05 22:45
*/
public class PropertiesTest {
@Test
public void test1(){
InputStream resourceAsStream = null;
try {
Properties properties = new Properties();
//此时的文件默认在当前的module下。
//读取配置文件的方式一:
/* FileInputStream fileInputStream = new FileInputStream("jdbc.properties");
properties.load(fileInputStream);*/
//读取配置文件的方式二:使用cLassLoader
// 配置文件默认识别为:当前module的src下
ClassLoader classLoader = PropertiesTest.class.getClassLoader();
resourceAsStream = classLoader.getResourceAsStream("jdbc1.properties");
properties.load(resourceAsStream);
String user = properties.getProperty ( "user" );
String password = properties.getProperty( "pass" );
System.out.println("user = " + user + ",pass = " + password);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (resourceAsStream!=null){
try {
resourceAsStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
通过发射创建运行时的对象
newInstance():
调用此方法,创建对应的运行时类的对象,内部调用了类的空惨构造器
要想此方法正常的创建运行时类的对象,要求:
1.运行时类必须提供空参的构造器
2.空参的构造器的访问权限得够。通常,设置为public.
在javabean中要求提供一个public的空参构造器。原因:
1.便于通过反射,创建运行时类的对象
2.便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器
动态性的展示
例:
package com.test;
import org.junit.Test;
import java.util.Random;
/**
* @author Alitar
* @date 2022-10-07 21:14
*/
public class dynamicTest {
@Test
public void test1() throws InstantiationException, IllegalAccessException {
int i = new Random().nextInt(3);
String classPath ="";
for (int j=0;j<=50;j++){
switch (i){
case 0:
classPath="java.util.Date";
break;
case 1 :
classPath="java.lang.Object";
break;
case 2:
classPath="com.test.Goods";
break;
}
System.out.println(getInstance(classPath));
}
}
public Object getInstance(String classPath) throws InstantiationException, IllegalAccessException {
Class<?> aClass = null;
try {
aClass = Class.forName(classPath);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return aClass.newInstance();
}
}
获取运行时类的丰富结构
package protect;
import java.io.Serializable;
/**
* @author Alitar
* @date 2022-10-07 21:30
*/
public class Creature implements Serializable {
private int height;
public int weight;
public void show(){
System.out.println("我是一个人!");
}
public void each(){
System.out.println("持有GV!");
}
}
package protect;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* @author Alitar
* @date 2022-10-07 21:44
*
* 获取当前运行时的属性结构
*/
public class FiledTest {
@Test
public void test1() throws InstantiationException, IllegalAccessException {
Class<Person> personClass = Person.class;
// 获取属性结构
// getFields()获取当前运行时类及其父类中声明为public访问权限的属性
Field[] fields = personClass.getFields();
for (Field f:
fields) {
System.out.println(f);
}
// getDeclaredFields()获取当前运行时类当中中声明的所有属性(不包含父类中的属性)
Field[] declaredFields = personClass.getDeclaredFields();
for (Field f:
declaredFields) {
System.out.println(f);
}
}
//权限修饰符 数据类型 变量名
@Test
public void test2(){
Class<Person> personClass = Person.class;
Field[] declaredFields = personClass.getDeclaredFields();
for (Field f:
declaredFields) {
// 1.权限修饰符
System.out.println(Modifier.toString(f.getModifiers()));
// 2.数据类型
System.out.println(f.getType().getName());
// 3.变量名
System.out.println(f.getName());
}
}
}
package protect;
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* @author Alitar
* @date 2022-10-07 21:58
*
* 获取运行时类的方法结构
*/
public class MethodTest {
@Test
public void test1(){
Class<Person> personClass = Person.class;
// getMethods()获取当前运行时类及其父类中声明为public访问权限的方法
Method[] methods = personClass.getMethods();
for (Method M :
methods) {
System.out.println(M);
}
System.out.println("******************");
// getDeclaredMethods()获取当前运行时类当中中声明的所有方法(不包含父类中的方法)
Method[] declaredMethods = personClass.getDeclaredMethods();
for (Method M :
declaredMethods) {
System.out.println(M);
}
}
//
// @Xxxxx
// 权限修饰符 返回值类型 方法名(参数列表)throws xxxException{}
@Test
public void test2(){
Class<Person> personClass = Person.class;
Method[] declaredMethods = personClass.getDeclaredMethods();
for (Method m:
declaredMethods) {
// 1.获取方法声明的注解
Annotation[] annotations = m.getAnnotations();
for (Annotation a:annotations){
System.out.println(a);
}
// 2.权限修饰符
System.out.print(Modifier.toString(m.getModifiers()) + "\t");
// 3.返回值类型
System.out.print(m.getReturnType().getName()+"\t");
// 4.方法名
System.out.print(m.getName());
System.out.print("(");
// 5.行参列表
Class<?>[] parameterTypes = m.getParameterTypes();
if (!(parameterTypes == null && parameterTypes.length==0)){
for (int i = 0;i<parameterTypes.length;i++) {
if (i==parameterTypes.length-1) {
System.out.print(personClass.getName() + "args_" + i);
break;
}
System.out.print(personClass.getName() + "args_" + i+",");
}
}
System.out.print(")");
// 6.抛出异常
Class<?>[] exceptionTypes = m.getExceptionTypes();
if (exceptionTypes.length>0){
System.out.print(" throws ");
for (int i=0;i<exceptionTypes.length;i++){
if (i==exceptionTypes.length-1){
System.out.print(exceptionTypes[i].getName());
break;
}
System.out.print(exceptionTypes[i].getName()+",");
}
}
System.out.println();
}
}
}
package protect;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
/**
* @author Alitar
* @date 2022-10-07 21:32
*/
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String[] value() default "hello";
}
package protect;
/**
* @author Alitar
* @date 2022-10-07 21:37
*/
public interface MyInstance {
void sss();
}
package protect;
import java.util.Objects;
/**
* @author Alitar
* @date 2022-10-07 21:30
*/
@MyAnnotation(value = "hi,my eat")
public class Person extends Creature<String> implements Comparable,MyInstance{
private String name;
public int age;
public Person() {
}
@MyAnnotation(value = "我是私有单属性")
private Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@MyAnnotation(value = "hi,my name")
private String showName(String name){
System.out.println("我的名字是" + name);
return name;
}
@Override
public String toString() {
return "Person{" +
"weight=" + weight +
", name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public void sss(){
System.out.println("我是一个接口提供的类");
}
private static void sss1(){
System.out.println("我是一个静态方法");
}
@Override
public int compareTo(Object o) {
return 0;
}
}
package protect;
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* @author Alitar
* @date 2022-10-07 22:40
*
* 获取构造器结构
*/
public class OtherTest {
@Test
public void test1(){
Class<Person> personClass = Person.class;
// getConstructors()获取当前运行时类中声明为public的构造器
Constructor<?>[] constructors = personClass.getConstructors();
for (Constructor<?> c:
constructors) {
System.out.println(c);
}
System.out.println();
// getDeclaredConstructors()获取当前运行时类中声明的所有构造器()
Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
for (Constructor<?> c:
declaredConstructors) {
System.out.println(c);
}
}
//获取当前运行时类的父类
@Test
public void test2(){
Class<Person> personClass = Person.class;
Class<? super Person> superclass = personClass.getSuperclass();
System.out.println(superclass);
}
//获取当前运行时类的带泛型的父类
@Test
public void test3(){
Class<Person> personClass = Person.class;
Type genericSuperclass = personClass.getGenericSuperclass();
System.out.println(genericSuperclass);
}
//获取当前运行时类的带泛型的父类的泛型
@Test
public void test4(){
Class<Person> personClass = Person.class;
Type genericSuperclass = personClass.getGenericSuperclass();
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
//获取泛型类型
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
System.out.println(actualTypeArguments[0].getTypeName());
Class c1 = (Class) actualTypeArguments[0];
System.out.println(c1.getName());
}
//获取运行时类实现的接口
@Test
public void test5(){
Class<Person> personClass = Person.class;
Class<?>[] interfaces = personClass.getInterfaces();
for (Class c :
interfaces) {
System.out.println(c);
}
System.out.println();
//获取运行时类的父类中的接口
Class<?>[] interfaces1 = personClass.getSuperclass().getInterfaces();
for (Class c :
interfaces1) {
System.out.println(c);
}
}
//获取运行时类所在的包
@Test
public void test6(){
Class<Person> personClass = Person.class;
Package aPackage = personClass.getPackage();
System.out.println(aPackage);
}
//获取运行时类声明的注解
@Test
public void test7(){
Class<Person> personClass = Person.class;
Annotation[] annotations = personClass.getAnnotations();
for (Annotation a :
annotations) {
System.out.println(a);
}
}
}
调用运行时类中指定的结构:属性,方法,
package protect;
import java.util.Objects;
/**
* @author Alitar
* @date 2022-10-07 21:30
*/
@MyAnnotation(value = "hi,my eat")
public class Person extends Creature<String> implements Comparable,MyInstance{
private String name;
public int age;
public Person() {
}
@MyAnnotation(value = "我是私有单属性")
private Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@MyAnnotation(value = "hi,my name")
private String showName(String name){
System.out.println("我的名字是" + name);
return name;
}
@Override
public String toString() {
return "Person{" +
"weight=" + weight +
", name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public void sss(){
System.out.println("我是一个接口提供的类");
}
private static void sss1(){
System.out.println("我是一个静态方法");
}
@Override
public int compareTo(Object o) {
return 0;
}
}
静态代理类
/**
* @author Alitar
* @date 2022-10-10 20:46
*/
public class ProxyBe implements ProxyInterface{
@Override
public void proxyCloth() {
System.out.println("生产了一批产品");
}
}
/**
* @author Alitar
* @date 2022-10-10 20:46
*
* 静态代理类
*
*/
public class ProxyIng implements ProxyInterface{
ProxyBe proxyBe ;
public ProxyIng(ProxyBe proxyBe) {
this.proxyBe = proxyBe;
}
@Override
public void proxyCloth() {
System.out.println("代理类一些前期工作");
proxyBe.proxyCloth();
System.out.println("代理类后期工作");
}
}
/**
* @author Alitar
* @date 2022-10-10 20:43
*/
interface ProxyInterface {
void proxyCloth();
}
/**
* @author Alitar
* @date 2022-10-10 20:42
*/
public class StaticProxy {
public static void main(String[] args) {
ProxyBe proxyBe = new ProxyBe();
ProxyIng proxyIng = new ProxyIng(proxyBe);
proxyIng.proxyCloth();
}
}
动态代理类
/**
* @author Alitar
* @date 2022-10-10 21:29
*/
public class ProxyUtil {
public void ss1(){
System.out.println("通用方法1");
}
public void ss2(){
System.out.println("通用方法2");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author Alitar
* @date 2022-10-10 21:07
*/
public class MyProxyHandler implements InvocationHandler {
private Object obj;//需要使用被代理类的对象进行赋值
public void bind(Object obj){
this.obj=obj;
}
//当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法: invoke()
// 将被代理类要执行的方法a的功能就声明在invoke()中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
ProxyUtil proxyUtil = new ProxyUtil();
proxyUtil.ss1();
//method: 即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
// obj:被代理类的对象
Object ReturnInvoke = method.invoke(obj, args);
proxyUtil.ss2();
return ReturnInvoke;
}
}
import java.lang.reflect.Proxy;
/**
* @author Alitar
* @date 2022-10-10 20:56
*
*动态代理类
*
* 要想实现动态代理,需要解决的问题?
* 问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
* 问题二:当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同名方法。
*
*/
public class ProxyFactory {
public static Object getProxyInstance(Object obj){
MyProxyHandler myProxyHandler = new MyProxyHandler();
myProxyHandler.bind(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),myProxyHandler);
}
}
/**
* @author Alitar
* @date 2022-10-10 21:12
*/
public class Factory {
public static void main(String[] args) {
ProxyBe proxyBe = new ProxyBe();
ProxyInterface proxyInstance = (ProxyInterface) ProxyFactory.getProxyInstance(proxyBe);
proxyInstance.proxyCloth();
}
}
java8新特性
Lambda表达式
Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
例
import org.junit.Test;
import java.util.Comparator;
/**
* @author Alitar
* @date 2022-10-11 18:56
*/
public class LambdaTest {
@Test
public void test1(){
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("这是一个lambda之前的测试");
}
};
runnable.run();
System.out.println("********************");
Runnable runnable1 = ()-> System.out.println("这是一个lambda之后的测试");
runnable1.run();
Comparator<Integer> comparator = new Comparator<>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
@Override
public boolean equals(Object obj) {
return false;
}
};
int compare = comparator.compare(12, 34);
System.out.println(compare);
System.out.println("********************");
Comparator<Integer> comparator1 = (o1,o2) -> Integer.compare(o1, o2);
Comparator<Integer> comparator2 = Integer::compare;
System.out.println(comparator1.compare(12,342));
System.out.println(comparator2.compare(232,2));
}
}
lambda表达式的使用
1.举例:(o1,o2) -> integer.compare(o1,o2);2.格式:
Lambda操作符 或 箭头操作符
左边: Lambda形参列表(其实就是接口中的抽象方法的形参列表)
右边: Lambda体(其实就是重写的抽象方法的方法体)
2.Lambda表达式的使用:(分为6种情况介绍
1.无参,无返回值
import org.junit.Test; import java.util.Comparator; /** * @author Alitar * @date 2022-10-11 18:56 */ public class LambdaTest { @Test public void test1(){ Runnable runnable = new Runnable() { @Override public void run() { System.out.println("这是一个lambda之前的测试"); } }; runnable.run(); System.out.println("********************"); Runnable runnable1 = ()-> System.out.println("这是一个lambda之后的测试"); runnable1.run(); } }
2.需要一个参数,但是没有返回值
public void test2(){ Consumer<String> stringConsumer = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; stringConsumer.accept("谎言"); Consumer<String> stringConsumer1 = (String s) -> System.out.println(s); stringConsumer1.accept("dadada"); }
3.类型推断
public void test2(){ Consumer<String> stringConsumer = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; stringConsumer.accept("谎言"); Consumer<String> stringConsumer1 = (s) -> System.out.println(s); stringConsumer1.accept("dadada"); }
4.若只需要一个参数时,参数的小括号可以省略
public void test2(){ Consumer<String> stringConsumer = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; stringConsumer.accept("谎言"); Consumer<String> stringConsumer1 = s -> System.out.println(s); stringConsumer1.accept("dadada"); }
5.需要两个或以上的参数,多条执行语句,并且可以有返回值
@Test public void test1(){ Comparator<Integer> comparator = new Comparator<>() { @Override public int compare(Integer o1, Integer o2) { System.out.println("********************"); return Integer.compare(o1, o2); } @Override public boolean equals(Object obj) { return false; } }; int compare = comparator.compare(12, 34); System.out.println(compare); System.out.println("********************"); Comparator<Integer> comparator1 = (o1,o2) -> { System.out.println("********************"); return Integer.compare(o1, o2) }; System.out.println(comparator1.compare(12,342)); }
6.当Lambda体只有一条语句时,return 与大括号若有,都可以省略
@Test public void test2(){ Consumer<String> stringConsumer = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; stringConsumer.accept("谎言"); Consumer<String> stringConsumer1 = System.out::println; stringConsumer1.accept("dadada"); }
3.Lambda表达式的本质:作为函数式接口的实例
函数式(Functional)接口
只包含一个抽象方法的接口,称为函数式接口。
你可以通过Lambda表达式来创建该接口的对象。(若Lambda表达式抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明)。
我们可以在一个接口上使用@Functionallnterface注解,这样做可以检查它是否是一个函数式接口。同时 javadoc也会包含一条声明,说明这个接口是一个函数式接口。
在java.util.function包下定义了Java8的丰富的函数式接口
消费型接口
Consumer
void accept(T t)
例
import org.junit.Test;
import java.util.function.Consumer;
/**
* @author Alitar
* @date 2022-10-11 19:41
*/
public class FunctionInterfaceTest {
@Test
public void test1(){
happyTimeConsumer(20, new Consumer<Double>() {
@Override
public void accept(Double aDouble) {
System.out.println("我是消费型接口"+aDouble);
}
});
happyTimeConsumer(500,money ->System.out.println("我是消费型接口"+money));
}
public void happyTimeConsumer(double money, Consumer<Double> consumer){
consumer.accept(money);
}
}
供给型接口
Supplier
get()
函数型接口
Function<T,R>
RappLy(T t)
断定型接口
Predicate
boolean test(T t)
例:
//根据给定的规则,过滤集合中的字符串。此规则由Predicate的方法决定
public List<String> filterString(List<String> list, Predicate<String> predicate){
ArrayList<String> strings = new ArrayList<>();
for (String arrayList: list){
if (predicate.test(arrayList)){
strings.add(arrayList);
}
}
return strings;
}
@Test
public void test2(){
List<String> strings = Arrays.asList("北京", "西京", "天津", "南京");
List<String> strings1 = filterString(strings, new Predicate<String>() {
@Override
public boolean test(String s) {
// contains方法:用于判断list集合是否包含某个元素
// containsKey方法:用于判断Map键中是否包含某个键
// containsValue方法:用于判断map中是否包含某个value值
return s.contains("京");
}
});
System.out.println(strings1);
List<String> strings2 = filterString(strings,s -> s.contains("京"));
System.out.println(strings2);
}
其他接口
方法引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。
要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!
格式:使用操作符“::”将类(或对象)与方法名分隔开来。如下三种主要使用情况:
对象::实例方法名
类::静态方法名
类::实例方法名
使用情景
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
使用格式
对象::实例方法名
@Test
public void test3(){
//情况一:对象∶∶实例方法
// Consumer中的void accept(T t)
// PrintStream中的void printLn(T t)
// lambda方法
Consumer<String> consumer = s -> System.out.println(s);
// 方法引用方法
Consumer<String> consumer1 = System.out::println;
consumer.accept("背景");
consumer1.accept("北京");
}
@Test
public void test4(){
// Supplier中的T get()
// person中的String getName( )
person per = new person("蔡徐坤",12);
// lambda方法
Supplier<String> supplier = ()->per.getName();
// 方法引用方法
Supplier<String> supplier1 =per::getName;
System.out.println(supplier.get());
System.out.println(supplier1.get());
}
类::静态方法名
@Test
public void test5(){
// 情况二:类::静态方法
// comparator中的int compare(T t1,T t2)
// Integer中的int compare(T t1,T t2)
Comparator<Integer> comparator = (t1,t2)->Integer.compare(t1,t2);
System.out.println(comparator.compare(123, 22));
Comparator<Integer> comparator1 = Integer::compare;
System.out.println(comparator1.compare(123, 22));
// Function中的RappLy( T t)
// Math中的Long round(Double d)
Function<Double, Long> function= aDouble -> Math.round(aDouble);
Function<Double, Long> function1= Math::round;
System.out.println(function.apply(2312.2));
System.out.println(function1.apply(23.2));
}
类::实例方法名
@Test
public void test6(){
//情况三:类∶:实例方法
// Comparator中的int comapre( T t1,T t2)
// String中的int t1.compareTo(t2)
Comparator<String> comparator = (t1,t2)->t1.compareTo(t2);
System.out.println(comparator.compare("ad", "dsc"));
Comparator<String> comparator1 = String::compareTo;
System.out.println(comparator1.compare("ad", "dsc"));
// BiPredicate中的booLean test(T t1, T t2);
// String中的boolean t1.equals(t2)
BiPredicate<String,String> biPredicate= (t1,t2)-> t1.equals(t2);
BiPredicate<String,String> biPredicate1= String::equals;
System.out.println(biPredicate.test("abc", "abc"));
System.out.println(biPredicate1.test("abc", "abc"));
// Function中的R appLy ( T t)
// person中的String getName();
Function<person,String> function = p->p.getName();
Function<person,String> function1 = person::getName;
System.out.println(function.apply(new person("余光", 12)));
System.out.println(function1.apply(new person("爱得发疯和", 12)));
}
使用要求
方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同!
构造器引用
和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。
抽象方法的返回值类型即为构造器所属的类的类型
@Test
public void test7(){
//构造器引用
// Supplier中的T get()
// person的空参构造器:person
Supplier<person> supplier = ()->new person();
Supplier<person> supplier1 = person::new;
System.out.println(supplier.get());
System.out.println(supplier1.get());
// Function中的R apply(T t)
Function<Integer,person> function = age->new person(age);
Function<Integer,person> function1 = person::new;
System.out.println(function.apply(1332));
System.out.println(function1.apply(231));
//BiFunction中的R apply( T t,u u)
BiFunction<String,Integer,person> biFunction= (name,age)->new person(name,age);
BiFunction<String,Integer,person> biFunction1= person::new;
System.out.println(biFunction.apply("Caixu", 12));
System.out.println(biFunction1.apply("徐俊", 243));
}
数组引用
数组看成是类的对象就可以了
@Test
public void test8(){
Function<Integer,String[]> function= length->new String[length];
Function<Integer,String[]> function1= String[]::new;
String[] apply = function.apply(5);
System.out.println(Arrays.toString(apply));
String[] apply1 = function1.apply(5);
System.out.println(Arrays.toString(apply1));
}
StreamAPI
Stream APl ( java.util.stream)把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作。简言之,Stream API提供了一种高效且易于使用的处理数据的方式。
为什么用Strean API
实际开发中,项目中多数数据源都来自于Mysql,Oracle等。但现在数据源可以更多了,有MongDB,Radis等,而这些NoSQL的数据就需要Java层面去处理。
Stream和 Collection集合的区别:Collection是一种静态的内存数据结构,而Stream是有关计算的。前者是主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU实现计算。
创建Strean的四种方式
1.创建Stream方式一:通过集合
default Stream
stream() :返回一个顺序流 default Stream
paraLleLStream( ) :返回一个并行流
2.创建Stream方式二:通过数组
调用Arrays类的static
stream stream(T[] array):返回一个流
3.创建Stream方式三:通过stream的of()
4.创建Stream方式四:创建无限流
迭代
public staticStream iterate(final T seed, final Unary0perator f) 生成
public staticStream generate(Supplier s)
Stream 的中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。
筛选与切片
filter(Predicate p)
接收Lambda,从流中排除某些元素
distinct()
筛选,通过流所生成元素的hashCode()和equals()去除重复元素
limit(long maxSize)
截断流,使其元素不超过给定数量
skip(long n)
跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与 limit(n)互补
映射
map(Function f)
接收一个函数作为参数,该函数会被应用到每个元
map ToDouble( ToDoubleFunction f)
素上,并将其映射成一个新的元素。
接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。
map Tolnt( TolntFunction f)
接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。
map ToLong(ToLongFunction f)
接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。
flatMap(Function f)
接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
排序
sorted()
产生一个新流,其中按自然顺序排序
sorted(Comparator com)
产生一个新流,其中按比较器顺序排序
Stream的终止操作
●终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如: List、 Integer, 甚至是void
●流进行了终止操作后,不能再次使用。
匹配与查找
allMatch(Predicate p)
检查是否匹配所有元素
anyMatch(Predicate p)
检查是否至少匹配一个元素
noneMatch(Predicate p)
检查是否没有匹配所有元素
findFirst()
返回第一个元素
findAny()
返回当前流中的任意元素
归约
reduce(T iden,BinaryOperator b)
可以将流中元素反复结合起来,得到一个值。返回T
reduce(BinaryOperator b)
可以将流中元素反复结合起来,得到一个值。返回Optional
备注: map和reduce的连接通常称为map-reduce模式,因 Google用它来进行网络搜索而出名。
收集
collect(Collector c)
将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
Collector接口中方法的实现决定了如何对流执行收集的操作(如收集到List、Set、Map)。
另外,Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例具体方法与实例如下表:
Optional类
Optional
Optional类的Javadoc描述如下:这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
创建Optional类对象的方法:
Optional.of(T t):创建一个Optional实例,t必须非空;
Optional.empty():创建一个空的Optional 实例
Optional.ofNullable(T t):t可以为null
判断Optional容器中是否包含对象:
boolean isPresent():判断是否包含对象
void ifPresent(Consumer<? super T>consumer):如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。
获取Optional容器的对象:
T get():如果调用对象包含值,返回该值,否则抛异常
T orElse(T other):如果有值则将其返回,否则返回指定的other对象。
TorElseGet(Supplier<? extends T> other):如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
TorElse Throw(Supplier<? extends X>exceptionSupplier):如果有值则将其返
回,否则抛出由Supplier接口实现提供的异常。
jdk9
模块化系统
jShell命令
多版本兼容jar包接口的私有方法
钻石操作筷的使用升级(泛型<>)
语法改进: try语句
String存储结构变更
便利的集合特性:of()(只读)
增强的Stream API
全新的HTTP客户端API
Deprecated的相关API
javadoc的HTML5支持
Javascript引擎升级: Nashorn
java的动态编译器
jdk11
判断字符串是否为空白
“ “.isBlank(); // true去除首尾空白
“ Javastack “.strip();// “Javastack”去除尾部空格
“ ]avastack “.stripTrailing();// “ Javastack”去除首部空格
“ Javastack “.stripLeading(); // “Javastack “复制字符串
“Java” .repeat(3);// “JavaJavaJava”行数统计
“A\nB\nc”.lines( ).count(); // 3
Optional
boolean isEmpty()
判断value是否为空JDK 11
ifPresentOrElse(Consumer<?
value非空,执行参数1功能;如果value为空,执行参数2功能
JDK 9super T>action, Runnable emptyAction)
Optionalor(Supplier<?extends Optional<? extends T>> supplier)
value非空,返回对应的Optional;alue为空,返回形参封装的Optional
JDK 9Stream
stream() value非空,返回仅包含此value的;否则,返回一个空的Stream
JDK 9
T orElseThrow()
value非空,返回value;否则抛异常
NoSuchElementExceptioJDK 10
- Post link: https://dy1320.top/2022/06/20/java/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.
GitHub Issues