Debug使用
Step into(F7):下一步,只有定义方法调用,就进入被调用的方法中
Step over(F8):下一步,只在本方法中下一步,即使有方法调用,也不进入被调用的方法中
Farce Step Into(Alt+shift+F8):只要经过方法就强行进入,包括系统自带方法
Step out(Shift+F8):从调用方法种出来
View breakpoints(Ctrl+Shift+F8):管理所有断点,查看和删除
Resume Program(F9):到下一个断点处,如果么有断点就执行到代码结束
mute breakpoints:屏蔽所有断点
switch要求byte、short、int、char、String(JDK1.8后)、枚举
形参是值传递
引用类型形参是地址传递,是new了一个新对象去指向地址
this();this调用构造器只能放在第一行且只有一个构造器时不能使用this();
super同理,从当前方法通过super()能访问父类构造器
2、Java内存空间
栈内存:保存所有的对象名称
堆内存:保存每个对象的具体属性内容
全局数据区:保存static类型的属性
全局代码区:保存所有的方法定义
3、static
不能调用任何非static类型的属性和方法,非static声明的方法可以调用static声明的属性和方法
static类型的方法在对象未被实例化时就可以被类名直接调用
也可以用实例化对象去调用方法(不建议
静态代码块的加载优先于静态方法
类加载首先调用类加载器,类加载的同时加载了静态区,静态加载先加载静态代码块再加载加载静态方法,然后加载构造器。
代码块
构造代码块:构造代码块优于构造方法执行,且多次执行构造器构造代码块会执行多次
静态代码块:static,优于主方法执行,优于构造代码块执行,且不论产生多少个对象只会执行一次
构造器私有,只提供静态方法
4、public static Singletin = new Singletin(); Singleton s1 = Singleton.getInstance();
无论对象怎么引用只产生了一个对象
为什么类内不能访问sout 系统规定
5、在外部访问内部类
外部类.内部类 内部类对象 = 外部类实例.new 内部类();
Outer.Inter inter = (new Outer()).new Inter(); new Outer.Inner2();//静态内部类访问
内部类定义后,生成class文件以”Outer$Inter.class"的形式存在的,在Java中只要文件看见"$",则在程序中替代为“.''。
和变量访问差不多
public class Outer { int num = 10; public class Inner{ int num = 20; public void num(){ int num = 30; System.out.println(num); System.out.println(Inner.this.num); System.out.println(new Outer().num); System.out.println(Outer.this.num); } } }
接口默认修饰符是public static final 方法默认是public abstract的
抽象类修饰符不能使用private、static、synchronized、native修饰
Random伪随机,数据库很大有固定排列
6.抽象类被继承时要实现抽象方法,且能拿到抽象类中的成员变量和成员方法和构造器
char类型初始化元素的默认值是不可识别字符’ ‘;打印不出来,指向ASCII编码表第0个位置
抽象类和接口的区别
区别 抽象类: 接口:
xxxxxxxxxx private boolean batchRemove(Collection<?> c, boolean complement) { //转成数组 final Object[] elementData = this.elementData; int r = 0, w = 0; boolean modified = false; try { //对元数组进行遍历 for (; r < size; r++) //如果complement为true则将c中包含集合元素放入0索引,即将与同于c的元素进行储存,不同的进行删除 //如果为flase则将原数组中不同于c的元素进行储存,相同的进行删除 if (c.contains(elementData[r]) == complement) elementData[w++] = elementData[r]; } finally { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws. if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } //将空的删除 if (w != size) { // clear to let GC do its work for (int i = w; i < size; i++) elementData[i] = null; modCount += size - w; size = w; modified = true; } } return modified;}java
组成:抽象方法、实例方法、普通方法、变量常量 抽象方法、常量
使用:extends子类继承抽象类 implements 子类实现接口
关系:抽象类可实现多个接口 接口不能继承抽象类,能继承多个接口
设计模式:模板设计 工厂设计,代理设计
局限:只能单继承 无局限
对象: 都通过对象的多态性产生实例化对象
实际: 作为一个模板, 作为一种标准或者能力
选择:能用接口就用接口
区别 | 抽象类: | 接口: |
---|---|---|
定义 | 包含抽象方法的类 | 抽象方法和常量的集合 |
组成 | 抽象方法、实例方法、普通方法、变量常量 | 抽象方法、常量 |
使用 | extends子类继承抽象类 | implements 子类实现接口 |
关系 | 抽象类可实现多个接口 | 接口不能继承抽象类,能继承多个接口 |
设计模式 | 模板设计 | 工厂设计,代理设计 |
局限 | 只能单继承 | 无局限 |
对象 | 都通过对象的多态性产生实例化对象 | |
实际 | 作为一个模板 | 作为一种标准或者能力 |
选择 | 能用接口就用接口 |
特殊:
类设计原则:一定不要去继承一个已经实现好的类,要么继承抽象类要么实现接口,如果接口和抽象类都可以去使用的话,那么优先使用接口,避免单继承的局限
原因:抽象类和普通类的最大区别在于强制
如果使用普通类,子类可以根据自己需求选择性的进行重写某些父类方法的重写,所以普通方法无法对子类重写方法进行限制,然而抽象方法却可以强制要求子类重写父类方法,因此实际开发中,不建议子类继承普通方法,之建议子类继承抽象类。
final
修饰局部变量
-
基本类型
只能被赋值一次,不能赋值第二次
-
引用类型,
地址固定,只能赋值一次,不能更改地址,但是可以更改地址值的内容
修饰成员变量
成员变量
-
初始化时赋值
-
或者初始化不赋值在所有构造器中赋值
-
方法中不能第二次赋值
Date
Date now = new Date(); long time = now.getTime();
Calender
月份0-11,星期0-6
Calendar cal = Calendar.getInstance(); cal.get(1);//获得年cal.get(Calendar.YEAR); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS"); System.out.println(sdf.format(cal.getTime())); char[]ch1 = "123456".toCharArray(); char[]ch2 = "45632321".toCharArray(); System.arraycopy(ch1,2,ch2,3,4); //源数组 源数组索引位置 目标数组 目标数组位置 数组长度
System
//毫秒 long start = System.currentTimeMillis(); //纳秒 long time = System.nanoTime(); System.exit(0);
系统集合扩大,基数是10,然后每次扩大1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
math
abs(num)绝对值
celi(double num)进一法 返回值位double
floor(double num)舍一法 返回值位double
pow(double a,double b) a的b次方 返回值double
PI
round(正数四舍五入)
Bigdecimal
BigDecial构造器中变量为数字或者字符串数字 BigDecimal b1 = new BigDecimal(10); BigDecimal b2 = new BigDecimal(3); System.out.println(b1.add(b2)); //加 System.out.println(b1.subtract(b2)); //减 System.out.println(b1.divide(b2,3,BigDecimal.ROUND_HALF_UP));//除 //divide(数据,小数点后留几位,四舍五入或者进一舍一) System.out.println(b1.multiply(b2)); //乘
包装类
调用Integer的valueof()方法时传入的数字在-128到127之间时会调用本身的final Interger[] cache数组,在类加载时初始化了一个-128到127的数组并进行new对象,指向的i+128的位置,后续如果再用同样数会像字符串一样去调用不会再创建
if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i);
Integer i1 = new Integer(23); Integer i2 = 22;//和i3 Integer i3 = Integer.valueOf(21);
System.out.println(Integer.toBinaryString(100)); //转换成二进制 转回来前面0b System.out.println(Integer.toOctalString(100)); //转换成八进制 转回来前面0 System.out.println(Integer.toHexString(100)); //转成十六进制 转回来前面0x
Exception
thow和thows
thows写在方法声明上
thow写在方法内部
thow抛出异常对象后面只能跟一个对象
thows可以抛出多个异常并且往方法是调用处都要抛出
当thow抛出的是运行时异常,并不需要thows抛出,当其他异常时需要thows抛出
父类方法无异常,子类重写方法不能抛出异常只能捕获异常
线程
运用Thread
MyThread1 myThread1 = new MyThread1(); myThread1.start();
start();启动线程不能用run();线程的运行需要本机操作系统的支持
如果一个线程start();两次会出现异常:IllegalThreadStateException
运行Runnable
MyThread2 myThread1 = new MyThread2("线程A"); Thread t1 = new Thread(myThread1); Thread t2 = new Thread(myThread1); t1.start(); t2.start();
Thread类继承Runnable类
实现Runnable有以下优势:
-
适合多个相同的程序代码的线程去处理同一资源的情况
-
避免Thread单继承的局限
-
增强程序的健壮性,代码能被多个线程共享,代码和数据是独立的
开发中能用接口则用接口实现
多线程的两种实现方及其区别,分别写程序验证实现方式
实现方式:都需要一个线程主类,这个主类通过实现Runnable类或者继承Thread类并且一定要重写run();方法
Thread类是Runnable接口的子类,使用Runnable避免单继承的局限,以及更加方便的数据共享
实现方式在上面:
Callable接口
此接口主要有返回值
MyThread3 myThread1 = new MyThread3(); FutureTask<String> task1 = new FutureTask<String>(myThread1); Thread(task1).start();
线程一般有5中状态
-
创建线程
-
就绪状态
-
运行状态
-
堵塞状态
-
死亡状态
Java程序每次运行至少启动几个线程
Java是多线程语言,每当执行一个类时,就会启动JVM,会启动一个main线程,一个是垃圾回收线程
synchronized能够保证同一时刻只有一个线程执行该段代码,保证并发
synchronized是Java的关键字,被Java语言原生支持,是最基本的互斥手段
synchornized(同步对象),正常用this,如果写其他类可能约束只有某类才能进入
IllegalMonitorStateException异常是因为wait()方法必须和synchronized一起用,且当前谁是锁的所有者谁才能去调用wait,如果不是则爆出此异常,如果notifyAll未用锁对象调用也会爆出异常
当生产者和消费者两个类去调用同一份资源时,资源要上锁,可以用资源类当锁,消费者生产者共用实现类中的一个锁对象,然后用此对象当锁。
sleep和wait区别 sleep()是Thread类定义下的静态方法,表示线程休眠,将机会让给其他线程,但是监控依然保持,休眠时间到自动恢复 wait()是Object类定义的方法,表示线程等待,一直到notify或者notifyAll才结束
concurrent(java下的安全类)
concurrent是方法内部用synchronized
wait被唤醒后会在睡的时刻继续进行而不是返回
lock锁
//定义Lock锁对象 private Lock lock = new ReentrantLock(); //2.4、定义监视器对象 private Condition con = lock.newCondition(); //上锁 lock.lock; con.signal;//唤醒一个等待的线程 con.signalAll//唤醒所有线程 con.await;//等待状态 lock.unlock;
线程池
Excecutors
Executor是工具类,方法是静态方法,可调用Executor.newFixedThreadPool(int poolNum);
Executor中submit方法
<T> Future<T> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)
Future类需要调用get()方法打印内容(内部没有重写toString方法)
Callable 和Runnable的区别
Callable有返回值,Runnabke无返回值
Callable用的是call()方法调用,而Runnable调用的是run()方法
Callable能抛异常,Runnable不能跑异常
public ThreadPoolExecutor(int corePoolSize, //核心线程 int maximumPoolSize, //最大线程数 long keepAliveTime, //存活时间 TimeUnit unit, //时间单位 BlockingQueue<Runnable> workQueue,//队列长度 ThreadFactory threadFactory, //创建线程工厂 RejectedExecutionHandler handler) {//存满后怎么处理
ExecutorService pool = new ThreadPoolExecutor(3, 5, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
ArrayList
ArrayList<泛型> list = new ArrayList<>(); list.add(E)//添加元素到尾部 list.add(index,E)//添加元素E到指定index位置 list.addAll(colloctions<? extends E>)//添加继承E的集合或者E集合本身 list.get(index)//获得index处索引的内容 list.size()//获得list数据的长度 list.get(index)//获得index处元素 list.remove(index)//移除索引处元素,返回删除的元素 list.remove(元素)//移除元素,返回boolean list.removeAll(元素)//移除所有元素,返回boolean list.set(index,新元素)将索引处元素改成新元素 list.indexOf(Object o)//返回第一次出现的指定元素的索引,没有返回-1 list.sublist(index1,index2)//返回一个List集合索引index1-index2 Collections.addAll(list,"zhangsan","zhangsan"); list.replaceAll(a->a.equals("zhangsan")?"张三":a);//和张三相同输出张三,否则输出本身
String
String 不可变的,因为字符串在1.9开始用字节数组取储存,字节数组不可变所以string不可变
String s = new String("abc"); String s1 = "abc"; String s2 = new String(byte[],0,len)//截取0到len长度的byte[] String s2 = new String(char[],0,len)//截取0到len长度的char[] s.charAt(index)//index处的字符 s.leng() //字符串长度 s.toCharArray() //返回字符数组 s.substring(index1,index2)//截取索引index1到index2的字符串并生成新的数组(包前不包后) s.substring(index)//截取index到结尾 s.replace(数据,新数据)//将字符串中所有数据改成新数据 s.replaceAll(正则,新数据)//所有符合正则表达式规则的数据改成新数据 s.split(正则表达式)//按照指定规则拆分成若干个字符串数组 s.equals(数据)//比较两个字符串显示的结果是否相同 s.toLowerCase()//全部变成小写 s.equalsIgnorCase()//忽略大小写判断是否相同 s.toUppCase()//全部换成大写 s.indexOf(数据)判段数据与s的字符是否相同,相同返回索引,不同返回-1 s.comparTo(数据)//比较s与数据是否相同,相同返回0,不同返回差值 s.startWith(数据)//比较开头是否与数据相同 s.getBytes()//s转成字节数据
replace和replaceAll的区别
replace支持字符和字符串的替换 replaceAll方法基于正则表达式的字符串替换
JVM编译优化机制
StringBuffer和StringBuilder区别
StringBuffer
-
当字符串进行修改的时候,需求使用StringBuffer和StringBuilder类
-
和String类不同的是,StringBuilder和StringBuilder类的对象能够多次的修改,并且不产生新的未使用对象
-
StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。
-
由于 StringBuilder 相较于 StringBuffer 有速度优势,多数情况下建议使用 StringBuilder类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。
Collection
调用增强for时编译时生成新的数组,对元素进行修改是新的集合的进行修改而不是直接对集合元素进行修改,只是用来进行遍历,不能进行增删改的遍历
当对迭代器进行增强for遍历使用for循环
可变参数:
当相同名字的可变参数和固定参数的方法重名
当参数是基本类型或者基本类型的一维数组进入固定参数名的方法,而其余的进入可变参数中
int[] num = {4,5,6}; int[][] n = {{4,4,4},{4,4,4}}; Test.fun(n);//可变参数 Test.fun(4);//单参 Test.fun(num);//单参 Test.fun(4,5,6);//可变参数 Integer[] num2 = {7,7,7}; Test.fun(num2);//可变参数
注意
集合特点(并发修改异常(迭代器))
next中:modCount是实际修改次数,当remove或者add时会增加一次
当在迭代器中使用list本身的remove时会出现并发异常,因为删除元素会记录modCount会增加,在下一次执行的时候会爆出并发一异常
而当删除倒数第二个元素无异常,当下次遍历时直接出去不会进入next();
rrayList<String> list = new ArrayList<>(); Collections.addAll(list,"张三","李四","王五","赵六"); Iterator<String> it = list.iterator(); while (it.hasNext()) { if ("李四".equals(it.next())){ // if ("王五".equals(it.next())){ // if ("赵六".equals(it.next())){ list.remove("李四");//出ConcurrentModificationException异常 // list.remove("王五");//无异常 // list.remove("赵六"); // it.remove(); } } System.out.println(list);
双链表
泛型
定义在方法时在修饰符后,返回值后面
定义在类后
定义在接口时,实现类要吗本身有该类型或者定义类型
class A implements C<String>{} class B<T> implements C<T>{} //方法 public <E> void method(){}
<T extends Comparable<? super T>>
T必须是Comparable的子类,Comparable<>中是T的父类
set
特点:底层是哈希表(数组+链表/红黑树),查询快,删减也快
-
无序
-
无索引:不能通过索引修改元素
-
不重复:通过hashcode和equals方法实现不重复
String中哈希码值相等但数值不一定相同,还需要调用eques方法
set原理:
set是Collection的一个子集
当set通过add()方法添加元素时会在本地生成一个16长度的数组,每个数组下面跟一个链条,如果数组的0.75被占用则会扩大数组,扩大数组是原来的2倍,并且生成新的数组,将原数组的数据重新进行排列,每当链表节点>8 并且数组元素数量>64,链表变成红黑树,然后会计算哈希值(int类型),然后让哈希值%16得到一个数字存放在对应数组下方,如果哈希值重复则会调用equals方法和该数组位置的每一个进行对比,如果重复则取消存放;
hash2倍
array1.5倍
StringBuilder2倍+2
HashMap
遍历:
Map<String, String> map = new HashMap<>(); map.put("张三","san"); map.put("李四","si"); map.put("王五","wu"); //迭代器 Iterator<String> it = map.keySet().iterator(); while (it.hasNext()) { String key = it.next(); System.out.println(key+"::::"+map.get(key)); } System.out.println("------------------"); //加强for for (String key : map.keySet()) { System.out.println(key+"===="+map.get(key)); } System.out.println("------------------"); //forEach map.forEach((key,value) -> System.out.println(key+"~~~"+value)); //调用entry遍历 Iterator<Map.Entry<String, String>> it2 = map.entrySet().iterator(); while (it2.hasNext()) { Map.Entry<String, String> entry = it2.next(); System.out.println("entry = " + entry); } System.out.println("--------------------"); for (Map.Entry<String, String> entry : map.entrySet()) { System.out.println("entry = " + entry.toString()); }
List构造器可接受Collection集合对象
public ArrayList(Collection<? extends E> c) {}
Propertise
是IO中唯一的双链集,是map子类Hashtable的子类
独有方法:
Properties prop = new Properties(); prop.setProperty("姓名","张三"); prop.setProperty("年龄","23"); prop.setProperty("地址","南极"); String age = prop.getProperty("年龄"); System.out.println("age = " + age); Set<String> stringPropertyNames = prop.stringPropertyNames(); for (String stringPropertyName : stringPropertyNames) { System.out.println(stringPropertyName+prop.getProperty(stringPropertyName)); }
IO流
BufferOutPutStream
缓冲流数组默认8192
缓冲流是存放一个8192的数组区域,将文件每次将文件读取8192个字节放入该数组区域,然后
编码与解码
编码:
ASCII、GBK、UTF-8
把字符转成字节
中文转字节是负数
bytes getBytes(){}
bytes getBytes(String 编码类型){}
解码:
把字节转成字符
构造方法
new String(bytes[]);
new String(bytes[],String 编码类型){}
ReadAndWriter
FileReader类:文件字符输入流,底层内部实现原理, FIleInputStream+平台默认编码
//Utf-文件转成GBK List<String> list = new ArrayList<>(); BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("day12-IO\\b1\\f5_sort.txt"), "UTF-8")); String line; while ((line = br.readLine())!=null){ List.add(line); } br.close(); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("day12-IO\\b1\\f1_sort.txt"), "GBK")); list.forEach(str -> { try { bw.write(str); bw.newLine(); } catch (IOException e) { e.printStackTrace(); } }); bw.close();
Wrinter中没有换行,要调用newLine方法内衣换行
调用读写流时用完要尽快关闭
序列化和反序列化
序列化前提:类必须实现Serializable接口
反序列化前提:类必须实现接口,必须存在类对应的class文件
静态不会被序列化static修饰
或者transient修饰的被忽略
序列化写入仅仅需要一次存入
oop.writeObject(list);
反序列化用集合直接去接并强转
List<Person> list2 = (List<Person>) oip.readObject();
Person p1 = new Person(23, "张三", '男'); Person p2 = new Person(24, "李四", '男'); Person p3 = new Person(25, "王五", '男'); List<Person> list = new ArrayList<>(); Collections.addAll(list, p1, p2, p3); ObjectOutputStream oop = new ObjectOutputStream(new FileOutputStream("day12-IO\\b1\\f2.txt")); oop.writeObject(list); oop.close(); ObjectInputStream oip = new ObjectInputStream(new FileInputStream("day12-IO\\b1\\f2.txt")); List<Person> list2 = (List<Person>) oip.readObject(); System.out.println(list2);
IOUtils
copy(InputStream)
FileWrinter和BufferedWriter区别
写入的都是字符流
FileWriter缓冲区是8192个字节当写到8192+1,而BufferedWriter缓冲区是8192*3+1个字节才会自动存入
FileWriter和BufferedWriter方法都没有真正往硬盘中写数据,存入的都是缓冲区,只有调用flush才会刷新(调用close方法也可以,内部是调用flush方法)
FileWriter调用writer()方法就会调用OutputStream中的writer()方法,而BuferedWriter只有再缓冲区满了才会调用OutputStreamWriter中的Writer方法,OutputStreamWriter主要是用于给字符转码的,并且会在缓冲区积累。
FileWriter没调用一次Writer就会进行一次转码,而BufferedWriter只有在缓冲区满了才会转码,这才是BufferedWriter高效的真正原因
域名被dns域名解析服务器解析
Annotation注解超类
注解
@Test(timeout = 1000)测试在1000毫秒后停止
断言
//第一个参数表示期望值 //第二个参数表示实际值 // 如果实际值和期望值相同,说明结果正确就测试通过,如果不相同,说明结果是错误的,就会报错 Assert.assertEquals( 期望值, 实际值); Assert.assertEquals("异常原因", 期望值, 实际值); //例如: int result = add(100,200); Assert.assertEquals(300, result);
单元测试
必须没有静态,必须没有返回值,必须没有参数
before:每个test之前都会运行before
after:在每个test之后都会运行after
枚举
枚举中大写的成员变量是用public final static修饰,成员变量必须写在枚举的后面,构造器私有,默认构造器是String和int类型
private 类名(String name,int num){} private com.ali.p7_anno.LightEnum(java.lang.String,int) 成员变量 public static final com.ali.p7_anno.LightEnum com.ali.p7_anno.LightEnum.RED~~16409 私有变量隐藏属性 private static final com.ali.p7_anno.LightEnum[] com.ali.p7_anno.LightEnum.$VALUES~~4122 静态方法 values()返回枚举类数组,静态方法可直接类名调用 public static com.ali.p7_anno.LightEnum[] com.ali.p7_anno.LightEnum.values() valueof()可用枚举返回整个枚举类 public static com.ali.p7_anno.LightEnum com.ali.p7_anno.LightEnum.valueOf(java.lang.String)
枚举中内置方法:
Enum.values()返回Enum数组可进行遍历
类加载的时机
按需加载
-
创建类的实例
-
类的静态变量或者静态变量赋值
-
类的静态方法
-
使用反射方式强制创建某个类或接口对应的java.lang.Class对象
-
初始化某个类的子类
-
直接用java.exe命令运行某个主类
类加载存在双亲委派
类加载只会加载执行一次
当用AppClassLoader系统类加载器会询问ExtClassLoader扩展加载器,而ExtClass Loader会询问BOotstrapClassLoader根类加载器,如果根类加载器加载则直接加载,不加载会返回给扩展加载器,扩展加载器不加载会返回给系统类记载器,如果系统类加载器不加载直接爆出类找不到异常
@Test public void boot(){ Class<String> clazz = String.class; ClassLoader classLoader = clazz.getClassLoader(); System.out.println(classLoader);//null } @Test public void ext(){ Class<DNSNameService> dnsNameServiceClass = DNSNameService.class; ClassLoader classLoader = dnsNameServiceClass.getClassLoader(); System.out.println(classLoader);//sun.misc.Launcher$ExtClassLoader@28a418fc } @Test public void app(){ Class<LoaderClassTest> loaderClassTestClass = LoaderClassTest.class; ClassLoader classLoader = loaderClassTestClass.getClassLoader(); System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2 ClassLoader parent = classLoader.getParent(); System.out.println(parent);//sun.misc.Launcher$ExtClassLoader@28a418fc ClassLoader parentParent = parent.getParent(); System.out.println(parentParent);//null }
类的创建
//第一种获取class方式 Class<?> c1 = Class.forName("pojo.User"); //第二种通过类名.Class获得 Class<User> c2 = User.class; //第三中通过getClass获得 Class<? extends User> c3 = new User().getClass();
反射
构造器反射,方法反射,常量反射都继承AccessibleObject,此类中有setAssess方法,可进行暴力反射
反射构造方法Constuctor
isAccessible;
Modifier工具类,可以确定修饰符的类
Modifier.isPublic(int mod);传入数字
construtor.getModifiers(); 返回修饰符
0-默认 1-public 2-private 4-procted 8-static 16-final 32-sychronized 64-volatile 128-transient 256-native 512-interface 1024-abstract 2048-strict
-
先有Class类对象
再用Class类调用getConstructor(Class对象)或者getDeclaredConstructor()生产Constructor对像
getDeclaredConstructors();返回Construtor[];
-
如果不是public需要调用setAccessible(Boolean)方法
-
用Constructor对象调用newInstance(构造器中的属性); 方法生成对象
Class<?> c = Class.forName("pojo.User"); //反射空参 Constructor<?> con = c.getConstructor(); User user = (User) con.newInstance(); System.out.println(user); System.out.println("-----------------------"); Constructor<?> con2 = c.getConstructor(String.class, int.class); User user2 = (User) con2.newInstance("张三",23); System.out.println(user2); System.out.println("==========================="); Constructor<?> decCon = c.getDeclaredConstructor(int.class); decCon.setAccessible(true); User user3 = (User) decCon.newInstance(23); System.out.println(user3); User user4 = (User) c.newInstance(); System.out.println(user4);
ClassLodader
ClassLoader classLoader = Test2MethodPro.class.getClassLoader(); InputStream is = classLoader.getResourceAsStream("config.properties"); Properties properties = new Properties(); properties.load(is);
ResourceBundle类
ResourceBundle resourceBundle = ResourceBundle.getBundle("config");
前面俩差不多
注释
接口AnnotatedElement是注解的超类
注释
注解是使用注解中的方法;由public abstract修饰
变量类型 变量名();
变量类型 变量名() default 初始值;
@MyAnnaTest2(name = "zja",c=MyAnnaTest2.class) public @interface MyAnnaTest2 { int age() default 0; String name(); Class c(); }
注释变量类型:
-
基本类型
-
String类型
-
Class类型
-
枚举类型
-
注解类型
-
以上类型的一维数组 例如String[]
注解使用必须完成所有变量的赋值
如果变量名是value且只有value一个未初始化时,可以直接写值
正常注解,类型 = 值 @MyAnnaTest2(name = "zja",c=MyAnnaTest2.class) //执行作用域 @Target(ElementType.TYPE)
元注解
@Target
用来限制自定义注解的作用域
TYPE - 类级别(接口、注解)
FIELD - 成员变量
METHOD - 方法
CONSTRUCTOR - 构造方法
LOCAL_VARIABLE - 局部变量
PACKAGE - 包
TYPE_PARAMETHER -
@Retention
ReTentionOPolicy
用来限制注解的生命周期
SOURCE - 源代码时期
CLASS - 字节码时期 (默认的)
RUNTIME - 运行时期
XML
头标签,必须为<?xml开头,以?>结束
必须在0行0列位置开始
<?xml version="1.0" coding="UTF-8"?>
元素(标签)
-
举例<bean></bean>
-
普通元素结构开始标签、元素体(标签体)、结束标签
元素体可以是元素,可以是文本
-
空元素:空元素只有开始标签没有结束标签,但元素可以自己闭合<c>
-
元素命名
-
区分大小写
-
不能使用空格,不能使用冒号
-
不建议以XML、xml开头
-
-
格式化良好的XML文档必须有一个根元素
注释<!-- -->或者ctrl+Shift+/
所有被要求的必须要完成赋值,但可以无序
<person name="张三" id="p001" age="18">
转义字符
XML约束
约束主要有dtd约束和schema约束
DTD约束即(Decument Type Definition),文档类型定义,约束XML文档
常见的DTD约束有SpringMVC和MyBaties
<?xml version="1.0" encoding="UTF-8"?> <!-- 传智播客DTD教学实例文档。 模拟spring规范,如果开发人员需要在xml使用当前DTD约束,必须包括DOCTYPE。 格式如下: <!DOCTYPE beans SYSTEM "bean.dtd"> --> //定义标签beans里面包含标签bean和import,*正则表示0-无数,顺序是先bean后import <!ELEMENT beans (bean*,import*) > //定义标签bean中的有property,一个至无数 <!ELEMENT bean (property*)> //标签property中可以定义#PCDATA 即<property> PCDATA内容 </property> <!ELEMENT property (#PCDATA)> //标签import可写 <!ELEMENT import (#PCDATA)> //#REQUIRED是必须要完成的 //ATTLIST是指属性 <!ATTLIST bean id CDATA #REQUIRED className CDATA #REQUIRED > <!ATTLIST property name CDATA #REQUIRED age CDATA #REQUIRED value CDATA #REQUIRED > <!ATTLIST import resource CDATA #REQUIRED>
定义标签beans里面包含标签bean和import,*正则表示0-无数,顺序是先bean后import
ELEMENT 标签、ATTLIST 属性
#REQUIRED是必须要完成的
#PCDATA 不由XML解析的数据,里面的数据不进行解析 <!ELEMENT import (#PCDATA)>
即<property> PCDATA内容 </property>
schema
1. <element>声明元素(标签) 2.每个元素都必须确定类型 complexType:复杂类型 simple Type:简单类型,一般不用,大部分都是复杂类型 3.需要明确子标签的出场顺序 <choice>选择 () <sequence>顺序 , <all>任意 minOccurs:最少出现次数 maxOccurs:最大出现次数,unbounded:不限制(没有边) 4.<attribute>用于给元素声明属性 use:设置属性使用 optional:可选 required:必须
-
Schema是新的XML文件约束
-
Schema要比DTD强大很多
-
Schema本身也是XML文档,但是Schema扩展名是xsl,而不是xml
-
Schema功能更强大,数据类型更完整
-
SChema支持名称空间package:定义包import:导包
<?xml version="1.0" encoding="UTF-8"?> <!-- 传智播客Schema教学实例文档。 模拟spring规范,如果开发人员需要在xml使用当前Schema约束,必须包括指定命名空间。 格式如下: <beans xmlns="http://www.itcast.cn/bean" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.itcast.cn/bean bean-schema.xsd" > --> <!-- 通过xmlns指定xsd文件的约束文件位置 -->
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.itcast.cn/bean" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.itcast.cn/bean" elementFormDefault="qualified"> <!-- 声明根标签 --> <element name="beans"> //完整类型 <complexType> //选择无序 最小0至最多没定义 <choice minOccurs="0" maxOccurs="unbounded"> <element name="bean"> <complexType> //有先后区别 <sequence minOccurs="0" maxOccurs="unbounded"> <element name="property"> <complexType> //属性 <attribute name="name" use="required"></attribute> <attribute name="value" use="required"></attribute> </complexType> </element> </sequence> <attribute name="id" use="required"></attribute> <attribute name="className" use="required"></attribute> </complexType> </element> <element name="import"> <complexType> <attribute name="resource" use="required"></attribute> </complexType> </element> </choice> </complexType> </element> </schema>
解析xml文件
调用org.dom4j的jar包
然后创建主要对象SAXReader
调用read方法得到Document对象
或者根标记getRootElement()
进行遍历
public static void main(String[] args) throws DocumentException { //得到beat.xml对象的流 InputStream is = Demo1ReadXml.class.getClassLoader().getResourceAsStream("beat.xml"); //创建SAXReader对象 SAXReader saxReader = new SAXReader(); //调用SAXReader的read方法转换成Document对象 Document document = saxReader.read(is); //获得根标记对象 Element rootElement = document.getRootElement(); //调用方法将该标记内的对象全部打印 getElement(rootElement); } /** * 将element标记下的所有标记和属性都打印出来 * @param element */ public static void getElement(Element element) { //调用elements方法得到当前标记下的所有标记 List<Element> elements = element.elements(); if (elements == null || elements.size() == 0){ return; } for (Element element1 : elements) { //调用attributes得到该标记下的所有attribute属性 List<Attribute> attributes = element1.attributes(); for (Attribute attribute1 : attributes) { //attrible中的属性 System.out.println(attribute1.getName()+"~~"+attribute1.getData().toString()); if (element1.isTextOnly()) { System.out.println(element1.getText()); } } getElement(element1); } } }
XPath
第三方工具(jar包)XPath: 作用: 快速查找xml文件中的一个/多个节点 注意: 必须依赖于dom4j 使用: 1.导入jar包 2.api的介绍 SAXReader类 空参构造: public SAXReader(){} 可以直接创建对象 public Document read(InputStream is): 加载xml文档到内存,生成一个Document对象 public List<Node> selectNodes("xpath表达式"),用来获取多个节点 public Node selectSingleNode("xpath表达式"),用来获取一个节点 xpath表达式常用查询形式 1.//AAA//DDD//BBB: 表示一层一层的,AAA下面 DDD下面的BBB 2.//BBB: 表示和这个名称相同,表示只要名称是BBB 都得到 BBB指的是标签名 3./*: 所有元素 4.查看第一个/最后一个元素 BBB[1]:表示第一个BBB元素 BBB[last()]:表示最后一个BBB元素 5.//BBB[@id]: 表示只要BBB元素上面有id属性 都得到 6.//BBB[@id='b1'] 表示元素名称是BBB,在BBB上面有id属性,并且id的属性值是b1
Lambda
函数式思想,强调做什么而不是用什么形式做
Lambda表达式的标准格式为:
(参数类型 参数名称) -> { 代码语句 }
格式说明:
-
小括号内的语法与传统方法参数列表一致:无参数则留空;多个参数则用逗号分隔。
-
->
是新引入的语法格式,代表指向动作。 -
大括号内的语法与传统方法体要求基本一致。
省略规则
在Lambda标准格式的基础上,使用省略写法的规则为:
-
小括号内参数的类型可以省略;
-
如果小括号内有且仅有一个参数,则小括号可以省略;
-
如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。
函数是接口
是指java中有且只有一个抽象方法的接口
java.util.function包下
Functionallnterface注解
Supplier<T>接口生产者
无参有返回值
T get();
Consumer<T>消费
有参无返回值
void accept(T t);
Function<T,R>
有参有返回值
R apply(T t); 可以得到T的另一个属性R
Predicate
真假判断
boolean test(T t);
Stream流
创建流
集合Collaction定义方法生产stream流
default Stream<E> stream() { return StreamSupport.stream(spliterator(), false); }
Arrays工具类
public static <T> Stream<T> stream(T[] array) { return stream(array, 0, array.length); }
集合数组都可以创建流
List list = new ArrayList(); System.out.println("list"+list.stream()); Map<String,String>map = new HashMap<>(); System.out.println("mapkey"+map.keySet().stream()); System.out.println("mapvalues" + map.values().stream()); System.out.println("mapentryset" + map.entrySet().stream()); String[] arr = {"张三","2"}; System.out.println("数组"+Arrays.stream(arr)); Arrays.stream(new int[]{1,2}); Stream.of("1","2","3");
Stream流方法:
流对象只能操作一次
filter():过滤
count():返回Stream个数
limit(int num):限制,取得前num个
skip(int num): 跳过前面num个
distinct:返回不重复的数
contact(s1,s2): 连接两个流变成一个流
map(Function<T,R>function),调用Function接口传入集合流返回新的集合流
strList.stream().map(new Function<String, Person> () { @Override public Person apply(String s) { String[] split = s.split("\\:"); return new Person(split[0],Integer.parseInt(split[1])); } }).forEach(System.out::println);
colloct(三个参数): 内部已经定义好了
Collectors.toList()返回List集合
Collectors.toMap() Collectors.toSet()
List<Person> collect = list.stream().map(s -> { return new Person(s.getName(), s.getAge() + 2); }).collect(Collectors.toList()); collect.forEach(System.out::println);