javaSE学习总结

//报错1
//System.out.println(num);
//声明4个变量
int num ;
num = 100;
System.out.println("num=" + num);



//细节2: 该区域的数据可以在同一类型范围内不断变化
// num = "tom";
// System.out.println("num=" + num);




//细节3: 变量在同一个作用域内不能重名
//int num ;


//细节4: 如果我们声明了一个变量,没有赋值,直接使用?
int num2;
System.out.println("num2=" + num2);






public class TestType2
{
public static void main(String[] args){
//基本数据类型强制转换
//注意:强制数据类型转换,会造成精度的损失
int i = (int)1.99;
System.out.println(i);

int j = 100;
byte s1 = (byte)j;
System.out.println(s1);


//细节:强转符号只针对于最近的操作数有效,
//往往会使用小括号提升优先级
int k = (int)(10 * 1.5 + 8 * 0.5);


//char类型可以保存 int的常量值,但不能保存int的变量值,
//需要强转
char a = 97;
char b = 20078;
int num100 = 97;
char c = (char)num100;//int => char
}
}




//在默认情况下,小数的常量值,是double
//float f = 1.2;//报错


//给一个小数常量值,后面加上 f,F就表示该常量值为float
float f2 = 1.2f;
double d1 = 1.2;
double d2 = 0.21;
double d3 = .51;//不推荐
//小数的科学计数法
double d4 = 5.12e2;
double d5 = 5.12e-2; 
System.out.println("d4=" + d4);//512.0
System.out.println("d5=" + d5);//0.0512




//演示三元运算符的使用
int a = 10;
int b = 20;
//执行流程如下
//1 先执行  a > b
//2. 如果 a> b 为true ,则返回 a++给result
//3. 如果 a> b 为false ,则返回 b--给result
int result = a > b ? a++ : --b;
System.out.println("result=" + result);




import java.util.Scanner;
public class TestInputDemo {
public static void main(String[] args){
//要求:可以从控制台接收用户信息,【姓名,年龄,薪水】
//1. 导入Scanner类
//2. 创建一个 Scanner 类的对象
//   System.in: 表示一个输入设备,即键盘
Scanner  scanner = new Scanner(System.in);
//3. 接收姓名,年龄,薪水
//   scanner.next() : 接收一个控制台输入的字符串
System.out.println("请输入你的名字:");
String name = scanner.next(); 


//   scanner.nextInt() : 接收一个控制台输入的整数
System.out.println("请输入你的年龄:");
int age = scanner.nextInt();


System.out.println("请输入你的薪水:");
double salary = scanner.nextDouble();
System.out.println("你输入的信息如下:");
System.out.println("你输入的 名字 :" + name);
System.out.println("你输入的 年龄:" + age);
System.out.println("你输入的 薪水 " + salary);
}
}






// 比如:~2=?  2&3=? 2|3=? 2^3=?


// ~2 : 按位取反 0->1, 1->0
// 1. 2的补码和原码  => 0000 0010
// 2. 取反操作          1111 1101
// 3. 1111 1101 => 反码  1111 1100 =》 原码 1000 0011 => -3





System.out.println(~2);//10
//1>>2:表示1这个数向右移动2位。
//1. 1的补码 0000 0001
//2.          000000 00 补码
//3.  结果0




System.out.println(1>>2);
//1<<2:表示1这个数向左移动2位。
//1. 1的补码 0000 0001
//2.          0000 0100 补码
//3.  结果4
System.out.println(1<<2);





//二进制的表示方法
int num1 = 0b1010; // 0 + 1 * 2 + 0 * 2 * 2 + 1 * 2 * 2 * 2 =10
//十进制
int num2 = 210; // 0 * 1 + 1 * 10 + 2 * 10 * 10
//八进制
int num3 = 01010; //表示  0 + 1 * 8 + 0 * 8 * 8 + 1 * 8 * 8 * 8 =》520
//16进制
//表示  0 + 1 * 16 + 0 * 16 * 16 + 1 * 16 * 16 * 16 =>4112
int num4 = 0x1010;
System.out.println(num1);//10
System.out.println(num2);//210
System.out.println(num3);//520
System.out.println(num4);//4112






// 9*9乘法表
// 看需求
/*
1) 首先是需要使用两重循环
2) 拆解
3) 先打印出 第一列
4) 然后根据规律,适当变化 当 i = 1时,一行打印是1个算式
当i = 2时,一行打印的是2个算式。。


*/
for (int i = 1; i <= 20 ;i++ ) {

for (int j = 1; j <= i ; j++ ) {
System.out.print( j + " * " + i + " = " + (j * i) + "\t");
}
System.out.println();
}






public static void main(String[] args){
/*
请用二维数组输出如下图形
0 0 0 0 0 0
0 0 1 0 0 0 ==》 1 arr[1][2]=1
0 2 0 3 0 0  ==> ....
0 0 0 0 0 0


*/


//1.定义二维数组
//  下面这句话的意思是有一个二维数组
// (1) 名称是 arr
// (2) 它含有四个一维数组 arr[0], arr[1], arr[2], arr[3]
// (3) arr[0] 这个一维数组中含有 6个元素分别是 arr[0][0],arr[0][1],arr[0][2],arr[0][3],arr[0][4],arr[0][5]
      
//     arr[1] 这个一维数组中含有 6个元素分别是 arr[1][0],arr[1][1],arr[1][2],arr[1][3],arr[1][4],arr[1][5]
int [][] arr = new int[4][6];
//2.给二维数组赋值,当没有赋值时,int类型二维数组默认为0
arr[1][2] = 1;
arr[2][1] = 2;
arr[2][3] = 3;
//3. 使用,遍历一下
for (int i = 0; i < arr.length ; i++ ) {
//这里再去遍历每一个一维数组
for ( int j = 0; j < arr[i].length ; j++ ) {
System.out.print(arr[i][j] + "\t");
}
      System.out.println();
    }
}
}








class BubbleSort {
public static void main(String[] args){
int arr[] = {24,69,80,57,13, -1, -100, 4567,-90};
//在没有排序前的情况
//看看结果如何
for (int j = 0; j < arr.length ; j++ ) {
System.out.print(arr[j] + "\t");
}
for (int i = 0; i < arr.length - 1 ; i++) {


for (int j = 0 ; j < arr.length - 1 - i ; j++) {


if (arr[j] > arr[j+1]) {
//交换
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}

System.out.println();
System.out.println();
//看看结果如何
for (int j = 0; j < arr.length ; j++ ) {
System.out.print(arr[j] + "\t");
}
}
}






/*
 * 使用enum关键字定义枚举类
 * 
 * 格式:enum 类名{
 * 
 * }
 * 
 * 说明:
 * 1.必须在枚举类的第一行声明枚举类对象
 * 2.枚举类的多个对象之间用","分开用";"结尾
 * 3.枚举类的构造器只能使用private修饰
 * 4.enum关键字继承的是java.lang.Enum类
 * 
 */










/*

*  values()方法:返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值。
valueOf(String str):可以把一个字符串转为对应的枚举类对象。
要求字符串必须是枚举类对象的“名字”。如不是,会有运行时异常:IllegalArgumentException。


*/






/*
 * 注解:注解可以用来对类和类中的结构进行补充说明,并不会改变原来的结构。
 * 
 * 一 常见的三个注解:
 * @Override : 只能用在方法上。用来说明该方法是重写父类的方法
 * @Deprecated : 用于表示某个元素已经过时
 * @SuppressWarnings : 抑制警告
 * 
 * 二 自定义注解
 * 格式:权限修饰符  @interface 注解名{
 *
 * }
 * 
 * 三 元注解:注解的注解。对注解进行补充说明的注解
 *  @Retention :  用于说明注解的生命周期
 *   SOURCE: 创建  - 编译期间
 *   CLASS: 编译期间 - 运行期间
 *   RUNTIME: 运行期间(如果要获取注解的内容,该注解必须是RUNTIME)
@Target : 用于说明该注解可以用于修饰哪些元素
@Documented(了解) : 该注解是否可以被javadoc所解析
@Inherited(了解) : 被它修饰的 Annotation 将具有继承性.
如果某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自动具有该注解.






/*
 * 
 * 单元测试:
 * 1.先导包 - JUnit4
 * 2.写一个方法 (必须是public且没有返回值,没有形参列表)
 * 3.将光标移动到方法名上,右键 - Run As - JUnit Test
 * 4.如果显示的是绿色条说明测试成功
 * 5.如果显示的是枣红色说明测试失败-代码中发生了异常
 * 6.一般我们会单独创建一个测试类去进行方法测试
 * 
 * 注意:1.类名不能是Test
 *   2.测试方法所在的类必须是public所修饰的
 * 
 */








/*
 * 
 * 包装类 : 针对八种基本数据类型 - 定义了相对应的包装类
 * 
 * 
 * 基本数据类型  , 包装类,String三者之间的转换
 * 
 */
public class WrapperTest {



/*
* 基本数据类型  -> 包装类
*/
@Test
public void test(){

// int a = 10;
// Integer integer = new Integer(a);
// System.out.println(integer);
//
// Integer integer2 = new Integer("11");
// System.out.println(integer2);

/*
* 运行时异常:数值格式化异常 - NumberFomatException
Integer integer3 = new Integer("a");
System.out.println(integer3);
*/

boolean b = true;
//注意:并没有发生异常
Boolean boo = new Boolean("aaaa");
System.out.println(boo);

}

/*
* 包装类 -> 基本数据类型

* xxxValue:(xxx基本数据类型)
*/
@Test
public void test2(){

Integer integer = new Integer(11);
int a = integer.intValue();
System.out.println(a);

Boolean boolean1 = new Boolean("true");
boolean boo = boolean1.booleanValue();
System.out.println(boo);

}

/*
* 拆箱 : 将包装类的对象直接赋值给基本数据类型

* 装箱 :将基本数据类型直接赋值给包装类的对象

* 注意: 只限于基本数据类型和包装类
*/
@Test
public void test3(){
//装箱
int b = 20;
Integer a = b;
System.out.println(a);

//拆箱
Integer number =  new Integer(20);
int c = number;
System.out.println(c);

/*
*虽然形参列表是Object类型但是也可以放入基本数据类型 因为自动装箱了
Person person = new Person();
//自动装箱
person.equals(20);
*/
}

/*
* 基本数据类型,包装类  -> String
*/
@Test
public void test4(){

int a = 10;
//基本数据类型转String  第一种方式
String str = a + "";
System.out.println(str);
//基本数据类型转String  第二种方式
str = String.valueOf(a);
System.out.println(str);


//包装类 - > String
Integer integer = new Integer("11");
String string = integer.toString();
System.out.println(string);
}

/*
* String -> 基本数据类型,包装类
*/
@Test
public void test5(){
String str = "11";
//将String转成包装类
Integer integer = new Integer(str);
System.out.println(integer);
//将String转成基本数据类型  Xxx(包装类).parseXxx(基本数据类型)
int a = Integer.parseInt(str);
System.out.println(a);
}

}






public class Demo {


public static void main(String[] args) {

//向上转型
A a = new B();
//编译看左边运行看右边
a.say();

//向下转型:为了调用子类特有的属性和方法
if(a instanceof C){
C b = (C)a;
}else{
System.out.println("哥们你眼睛没问题吧");
}
}
}


/*
 * 
 * 多态的前提: 要有继承,要有方法的重写
 * 
 * 
 */


class A{


//public int age;
private void show(){

}

public void say(){

}
}




class C extends A{

public void say(){

}
}


class B extends A{

/*
* 注意:子类不可以重写父类中被private修饰的方法
*/
// @Override
// private void show() {
//
// }







public int age;
@Override
public void say(){
super.say();
//省略的是this.
System.out.println(this.age);
}
public void info(){
}
}




/*
public int length() //字符串的长度(重点)
public char charAt(int index) //根据索引值获取对应的字符(重点)
public boolean equals(Object anObject) //比较两个字符串的内容(重点)
public int compareTo(String anotherString) //比较两个字符串的大小(内容)
public int indexOf(String s)// s在当前字符中索引值开始的位置,如果没有返回-1(重点)
//从当前字符串中startpoint索引位置开始查找s
//如果能找到直接返回索引值,如果找不到返回-1
//如果在当前字符串中有多个s,从开始查找索引位置开始的第一个s的位置
public int indexOf(String s ,int startpoint)
public int lastIndexOf(String s)
//从当前字符串中startpoint索引位置开始查找s
//如果能找到直接返回索引值,如果找不到返回-1
//如果在当前字符串中有多个s,从开始查找索引位置往前开始的第一个s的位置
public int lastIndexOf(String s ,int startpoint)
//当前字符串是否以prefix开头,如果是返回true否则返回false
public boolean startsWith(String prefix)
//当前字符串是否以suffix结尾,如果是返回true否则返回false
public boolean endsWith(String suffix)

public boolean regionMatches(int firstStart,String other,
int otherStart ,int length)
*/








/*
*  //截取子串从当前字符串的startpoint的位置开始截取
*  public String substring(int startpoint)
*  //截取子串从当前字符串的start的位置到end的位置 (包头不包尾)
public String substring(int start,int end)(重点)
//把当前字符串中oldChar全部替换成newChar(重点)
pubic String replace(char oldChar,char newChar)
//把当前字符串中old全部替换成new
public String replaceAll(String old,String new)
//将字符串中两端的空格去掉
public String trim()(重点)
//将当前字符串和str进行拼接
public String concat(String str)
//当前字符串中是否含有s(重点)
public boolean contains(CharSequence s)
//将当前字符串安照某个字符进行切割(重点)
public String[] split(String regex)






/*
 * 将字符串反转
 */
@Test
public void test(){
String str = "abcdefg";
String str2 = "";
for (int i = str.length() - 1; i >= 0; i--) {
char charAt = str.charAt(i);
str2 += charAt;
}
System.out.println(str2);
}
 
/*






/*
 * 
 * String:是一个不可变的字符序列
 * 
 * 1.String类是final修饰的 - 不能被继承
 * 2.实现了Serializable接口 - 为了序列化
 * 3.实现了Comparable接口 - 比较内容
 * 4.实现了CharSequence接口 - 有根据索引值获取相应的字符和长度的方法
 * 5.String底层使用了char类型的数组来存放数据并且该数组是用final修饰的








/*
* String:不可变的字符序列,char[]保存数据并且数组是用final修饰的
* StringBuffer:可变的字符序列,底层是用char[]保存数据的,线程安全的
* StringBuilder:可变的字符序列,底层是用char[]保存数据的,线程不安全的


* 注意:如果往StringBuffer中存放的数据超过了数组的长度,那么会进行扩容,扩容到原来的2倍 + 2;

* String,StringBuffer,StringBuilder三者之间的效率(字符串拼接)? StringBuilder >
* StringBuffer > String
*/







/*
* StringBuffer append(String s), StringBuffer append(int n) , StringBuffer
* append(Object o) , StringBuffer append(char n), StringBuffer append(long
* n), StringBuffer append(boolean n), //在当前数组的index位置插入str StringBuffer
* insert(int index, String str) //将内容进行反转 public StringBuffer reverse()
* //将当前数组startIndex到endIndex的位置上的元素进行删除(包头不包尾) StringBuffer delete(int
* startIndex, int endIndex)n索引 //获取当前数组中位置上的元素 public char charAt(int n )
* //将当前数组中n索引位置上的元素替换成ch public void setCharAt(int n ,char ch)
* //将当前数组中startIndex到endIndex位置上的元素替换成str (包头不包尾) StringBuffer replace( int
* startIndex ,int endIndex, String str) public int indexOf(String str)
* public String substring(int start,int end) public int length()

*/


java.util.Date
* 两个构造器
* new Date();获取当前时间
* new Date(long time);获取time对应的时间
*  两个方法:
* 1.toString(); 输出时间//Wed Apr 18 16:51:38 CST 2018
* 2.getTime(); 返回当前时间所对应的毫秒数

* java.sql.Date --> 往数据库插入的时间都是sql下Date
*
* 一个构造器:
* new Date(long time); //获取time对应的时间
* 两个方法
* toString();输出时间 //2018-04-18
* getTime();获取时间对应的毫秒数

*/






/*
* System类提供的public static long currentTimeMillis()
* 用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差
*/




/*
* Math类:提供了一系列静态方法用于科学计算;其方法的参数和返回值类型一般为double型
*/
/*
* Integer类作为int的包装类,能存储的最大整型值为2^31−1,
* BigInteger类的数值范围较Integer类、Double类的数值范围要大得多,
* 可以支持任意精度的整数。
*/
/*
* 一般的Float类和Double类可以用来做科学计算或工程计算,
* 但在商业计算中,要求数字精度比较高,故用到java.math.BigDecimal类。
* BigDecimal类支持任何精度的定点数。
*/




/*
* java.text.SimpleDateFormat

* 两个方法:
* format(Date d):将时间转成字符串
* parse(String s):将字符串转成Date类型的时间

* java.text : 包下都是关于国际化的类


*


/*
 * 
 * java集合(容器):用来存储数据
 * 
 * 一 容器
 * ①数组   ②集合
 * 
 * 1.数组的特点:
 * ①长度不可变
 * ②数组中所有的数据类型都是一样的
 *  2.数组的缺点:
 *   ①数组一旦初始化长度不可变
 *   ②数组中存放的数据类型单一
 *   ③数组中的API太少,例如没有 删除,添加,修改.....操作不方便
 *      ④数组中存储的数据都是有有序的,对于无序的无能为力。
 *      
 * 二  Collection
 * |---Collection - 单例集合
 * |-----List :存储的数据是有序的,且可重复的。
 * |-----Set :存储的数据是无序的,且不可重复的。
 */
//toArray() 将当前集合转成数组


/*
* retainAll(Collection c):

* 从当前集合中删除和c集合中不相同的元素。只保留相同的元素
*/
/*
* remove(Object o) : 从当前集合中删除元素o
* 注意:如果当前集合中有多个o 只会删除一个

* removeAll(Collection c) : 从当前集合中删除 和 c集合交集(相同)的元素
*/
/*
* equals(Object c) : 当前集合中的元素和c集合中的元素是否一样(个数和内容)
*/


//containsAll(Collection c)
//当前集合中是否包含了c集合中的所有元素
//注意:当前集合中存在的元素和c集合中的相同元素(多个)都认为是包含的。
//contains(Object o) 当前集合中是否包含了o元素 如果包含了返回true 反之 false
//注意:往Collection中添加的引用数据类型   必须重写equals方法 进行比较




/*
 * 增强for循环 :只能用于数组和集合
 * 
 * 格式:
 * for(元素的类型   临时变量  : 数组/集合的对象){
 * 
 * }
 */
/*
* Iterator 接口 用来遍历集合中的元素
* hasNext() : 是否还有下一个元素
* next() : ①指针下移  ②返回当前指向的元素
*/


//al.remove(1); //删除当前集合对应的索引值上的元素。










/*
 *   |----Collection
 *   
 *   |----List : 存储的元素是有序的且可重复的
 *   
 *   |----Set : 存储的元素是无序的且不可重复的
 *   
 *   一  List接口API
 *   
 */
public class ListTest {


/*
//将ele元素插入到当前集合的index位置上
*  void add(int index, Object ele)
//将eles中的所有元素插入到当前集合中的index位置上
boolean addAll(int index, Collection eles)
//获取当前集合index位置上的元素
Object get(int index)
//获取obj元素在当前集合中的索引值,找不到返回-1 (从前往后找,如果有多个返回第一个元素的索引值)
int indexOf(Object obj)
//获取obj元素在当前集合中的索引值,找不到返回-1 (从后往前找,如果有多个返回第一个元素的索引值)
int lastIndexOf(Object obj)
//删除当前集合中index位置上的元素,并将返回删除的元素
Object remove(int index)
//将当前集合中index位置上的元素替换成ele,并返回替换前的元素
Object set(int index, Object ele)
//将当前集合中fromIndex到toIndex位置上的所有元素截取 并 返回一个新的list集合(包头不包尾)
List subList(int fromIndex, int toIndex)
ArrayList al = new ArrayList();//创建一个初始化长度为10的数组
ArrayList al2 = new ArrayList(20); //创建一个初始化长度为20的数组





/*
//向集合的头部添加元素
*  void addFirst(Object obj)
*  //向集合的尾部添加元素
void addLast(Object obj) 、
//获取集合头部的元素
Object getFirst()
//获取集合尾部的元素
Object getLast()
//从当前集合删除头部元素 并将头部元素返回
Object removeFirst()
//从当前集合删除尾部元素 并将尾部元素返回
Object removeLast()
*/




/*
 * 
 *  |----Collection
 *  
 *   |----List
 *  
 *   |----Set : 存储的元素是无序的且不可重复的
 *  
 *   |----HashSet(主要实现类)
 *  
 *   |----LinkedHashSet:继承了HashSet,底层实现原理和HashSet一样。
  但是LinkedHashSet可以安照元素添加的顺序进行遍历。因为LinkedHashSet
  底层维护了一对指针(链表)用来记录元素添加的顺序。
 *  
 *   |----TreeSet
 *  
 *  无序的:不是指的随机性,根据hash算法算出的hashCode值来决定在数组中存放的位置。  
 *  不可重复的:调用equals方法进行比较。如果返回是true认为两个对象相同。反之不相同。
 *  
 *  [面试题]HashSet的底层实现原理?
 *   当我们向HashSet中存放数据a时,会先根据该对象中的hashCode方法返回的值决定存放在数组中的位置。
 *  如果存放的位置没有其它元素那么直接存放。如果存放的位置已经有了其它元素b时,会调用a的equals方法进行内容的比较。
 *  如果返回的是true那么认为两个元素是相同的则不能再次存放。如果返回的是false那么认为两个元素不同。以链表的形式进行
 *  存放。
 *  


/*
* LinkedHashSet:继承了HashSet,底层实现原理和HashSet一样。
* 但是LinkedHashSet可以安照元素添加的顺序进行遍历。因为LinkedHashSet
* 底层维护了一对指针(链表)用来记录元素添加的顺序。
*/




/*
* TreeSet : 
* 1.TreeSet可以对元素进行排序
* 要求:元素的类须必须一致
* 2.排序有两种方式:自然排序  vs 定制排序
* 2.1自然排序
* ①实现Comparable接口
* ②重写compareTo方法
* ③安照属性进行排序
* ④添加元素








/*
 * Arrays:工具类,用来处理数组的
 */
public class ArraysTest {


/*
* 数组 -> 集合
*/
@Test
public void test(){

String[] str = {"aa","bb"};
//Arrays 用来处理数组的工具类
List<String> asList = Arrays.asList(str);
System.out.println(asList.size());
}

/*
* equals(int[] a,int[] b);判断两个数组是否相同(内容,位置,个数)
*/
@Test
public void test2(){
int[] number = {1,2,3,4,5};
int[] number2 = {1,3,2,4,5};
boolean equals = Arrays.equals(number, number2);
System.out.println(equals);
}

/*
* String toString(int[] number);返回一个包含了所有数组内容的字符串
*  用来输出数组中元素的信息
*  
*  fill(int[] a, int val);将a数组中所有的元素全部替换成val
*/
@Test
public void test3(){
int[] number = {3,1,18,35,5};
//fill(int[] a, int val);将a数组中所有的元素全部替换成val
//Arrays.fill(number, 5);


//String toString(int[] number);返回一个包含了所有数组内容的字符串
// String string = Arrays.toString(number);
// System.out.println(string);


//对数组内容进行排序
Arrays.sort(number);
System.out.println(Arrays.toString(number));

//二分法查找 :int binarySearch(int[] a,int key)
//注意:二分法查找前,必须进行排序
int index = Arrays.binarySearch(number, 18);
System.out.println(index);

}
}








/*
 * TreeSet : 
 * 1.TreeSet可以对元素进行排序
 * 要求:元素的类须必须一致
 * 2.排序有两种方式:自然排序  vs 定制排序
 * 2.1自然排序
 * ①实现Comparable接口
 * ②重写compareTo方法
 * ③安照属性进行排序
 * ④添加元素
 * 2.2 定制排序
 * ①创建一个Comparator实现类的对象
 * ②将Comparator对象传入TreeSet的构造器中
 * ③重写compare方法
 * ④安照属性进行排序
 * ⑤添加元素
 * 3.TreeSet底层是用红黑树进行数据存储的。
 * 
 * [思考]两种排序方式哪个好?两种方式都存在的情况下谁起作用。
 * 两种排序都有的情况下,定制排序起作用。
 * 两种方式定制排序好因为更灵活。
 */








/*
* 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中
boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值










/*
 * |----Map
 * |----HashMap(主要实现类) : 底层是用数组来存放数据的(数组 +  链表),线程不安全的
 * HashMap中可以存放null值
 * 
 * |----LinkedHashMap:继承了HashMap底层实现和HashMap一样。
 * LinkedHashMap可以安照添加元素的顺序进行遍历。因为底层维护了一张链表用来记录存放的元素的顺序。
 * 
 * |----TreeMap:用来对Key中的元素进行排序。
 * 
 * |----Hashtable : 底层是用数组来存放数据的(数组 +  链表),线程安全的
 * Hashtable中不可以存放null值
 * 
 * |----Properties : 用来读取配置文件中的内容。读取的内容都是字符串。
 * key和value都是String类型
 * 
 * 1.Map中的Key是无序的且不可重复的。如果是自定义类的需要重写equals和hashCode方法
 * 2.Map中的value是无序的可重复的。如果是自定义类需要重写equals方法
 * 3.一个Key和一个Value可以看成是一个Entry
 * 
 * 4.HashSet底层就是一个HashMap
 * 
 * [面试题]HashMap与Hashtable的区别?
 * 
 * [面试题]HashMap的底层实现原理?
 * 当我们向HashMap中存放一个元素(k1,v1),首先会根据k1的hashCode方法来决定在数组中存放的位置。
 * 如果当前位置没有其它元素则直接存放。如果当前位置有其它元素(k2,v2),会调用k1的equals方法和k2进行对比。
 * 如果返回值是true则代表内容相同,那么v1会覆盖v2.如果返回的是false则以链表的形式进行存放。
 * 当链表的长度为8时,链表将会改成红黑树进行存放。
 * 
 * 4.HashMap扩容:
 * 创建一个空参的构造器。那么底层默认创建一个长度为16加载因子为0.75。当我们向集合中添加元素
 * 超过12时会进行扩容,扩容为原来大小的2倍。
 * 
 */











/*
* Properties:用来读取配置文件的内容
*/
@Test
public void test8(){
FileInputStream fis = null;
try {
//第一步创建Properties的对象
Properties properties = new Properties();
//创建一个文件
File file = new File("person.properties");
//创建一个输入流
fis = new FileInputStream(file);
//第二步 加载一个输入流
properties.load(fis);
//第三步根据key值获取value值
String name = properties.getProperty("name");
String age = properties.getProperty("age");
System.out.println(name + " " + age);
} catch (Exception e) {

}finally{
//关流
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}








/*
* 默认创建一个数组长度为16,加载因子为0.75
*/
new HashMap();
/*
* 默认创建一个数组长度为30 ,加载因子为0.75
*/
new HashMap(30); 






/*
//添加元素,如果添加的key已经存在,那么后面添加的key的value会把前边的key的value进行覆盖
//注意,如果key是自定义类需要重写equals和hashCode方法
// 如果是value需要重写equals方法
*  Object put(Object key,Object value)
*  //根据key删除当前集合中的元素
Object remove(Object key)
//将t集合中的所有元素添加到当前集合中
void putAll(Map t)
//清除当前集合中所有的元素
void clear()





/*
//根据key值获取value值
*  Object get(Object key)
*  //当前集合是否包含了key
boolean containsKey(Object key)
//当前集合是否包含了value,如果value是自定义类必须重写equals方法
boolean containsValue(Object value)
int size()
boolean isEmpty()
boolean equals(Object obj)








/*
*  Set keySet() //获取当前集合中所有的key
Collection values() //获取当前集合中所有的value
Set entrySet()


*/








/*
 * 一  LinkedHashMap:继承了HashMap底层实现和HashMap一样。
 * LinkedHashMap可以安照添加元素的顺序进行遍历。因为底层维护了一张链表用来记录存放的元素的顺序。
 * 
 *  1. LinkedHashSet底层就是一个LinkedHashMap.
 * 
 * 三  TreeMap
 *  1. TreeSet
 */








/*
一 在集合中使用泛型
二 自定义泛型类 自定义泛型接口自定义泛型方法
三 泛型在继承上的体现
四 通配符的使用




/*
* 为什么要使用泛型?
* 1. 解决元素存储的安全性问题
  2. 解决获取数据元素时,需要类型强转的问题


*/






/*
* 在集合中使用泛型
* 1.如果没有指明泛型的类型那么默认是Object
* 2.在创建对象的时候如果指明了泛型的类型,那么该类中所有用到泛型的地方全部都具体化了。
*/






//如果名字相同按照年纪排序
// int compareTo = stu.name.compareTo(stu2.name);
// if(compareTo == 0){
// return stu.age - stu2.age;
// }
// return compareTo;








/*
 * 自定义泛型类
 * 
 * 一般自定义泛型类 指明泛型的类型都用大写字母  比如:K ,T ,V ,E
 * 
 * 注意:
 * 1.异常类型不能使用泛型
 * 2.静态方法中不能使用泛型
 */




public void test() throws Exception{
File file2 = new File("D:\\aa\\bb\\123.txt");
//获取文件的父目录
File parentFile = file2.getParentFile();
//判断父目录是否存在,如果不存在,则创建。
if(!parentFile.exists()){
parentFile.mkdirs();
}
//注意:创建的文件的父目录必须存在,否则创建不成功
file2.createNewFile();
}
}






/*
* 泛型类:
* 思考?如何给父类指明泛型类型

* 第一种方式:子类在继承父类的时候,可以直接声明父类的泛型类型。
* public class Student extends Person<String>

* 第二种方式:子类在继承父类的时候,可以通过子类对象来指明父类的泛型类型
* public class Student<T> extends Person<T>

*/






//第一种方式:直接指明父类的泛型类型
// Student student = new Student();
// student.setT("aaaa");
// String t = student.getT();
// System.out.println(t);

//第二种 通过子类指明父类的泛型类型


public class Person<T> {


T t;


public T getT() {
return t;
}


public void setT(T t) {
this.t = t;
}


public void add(T t){
//添加到数据库
//添加到集合
}

/*public void add(Student stu){
//添加到数据库
//添加到集合
}
public void add(Employee  e){
//添加到数据库
//添加到集合
}
public void add(Person p){
}*/
public void delete(T t){
}
}






/*
* 泛型方法
* 注意:泛型方法是可以使用static来修饰的,因为调用方法的时候我们就知道了泛型的类型
*/




/*
* 编译错误  : 因为调用该方法时,不能够确定泛型的类型
*/
/*
public static T getT3(){
return t;
}
*/








/*

* 如果类B继承了类A 那么类B和类A是具有子父类关系的

* G<A>和G<B>不具有子父类关系。


* 通配符 ?

* ?是所有泛型的父类。
*  使用了泛型类型是通配符的类型的集合,
1.不能再存放任何数据(除null以外)。
2.可以遍历所有的元素

<? extends Number> : 泛型的类型只能是Number和Number的子类
<? extends Comparable>只允许泛型为实现Comparable接口的实现类的引用调用
<? super Number> :泛型的类型只能是Number和Number的父类

*/




/*
* 使用了泛型类型是通配符的类型的集合,
* 1.不能再存放任何数据(除null以外)。
* 2.可以遍历所有的元素

*/




/*
 * 
 * File类:java.io.File
 * 
 * 1.File可以用来表示一个文件或目录,例如:.avi  .mp3  .mp4 .txt
 * 2.File可以用来新建,删除 ,修改  文件和目录  等操作......
 * 3.如果要对文件内容进行读取和写入,需要使用IO流。一般我们都会将File作为参数传入到IO流对象的构造器中。
 * 
 * 
 */


/*
* File类的常见构造器

* 绝对路径 :包含盘符在内的完整路径
* 相对路径 :相对某个项目的路径

*/


System.out.println(file.exists()); //是否存在
System.out.println(file.canWrite());//能不能写
System.out.println(file.canRead()); //能不能读
System.out.println(file.isFile()); //是不是一个文件
System.out.println(file.isDirectory()); //是不是一个目录







/*
* 第三波
*  createNewFile()
delete()


*/
@Test
public void test4(){
File file = new File("bbb.txt");
try {
if(file.exists()){
//如果文件存在则删除
file.delete();
}else{
//创建一个文件
file.createNewFile();
}

} catch (IOException e) {
e.printStackTrace();
}
}








/*
* 第四波
*  lastModified() //获取最后一次修改的时间
length() //文件大小








/*
* 第五波 -操作与目录相关
*  mkdir() //创建目录,如果父目录存在则创建成功,否则创建失败
mkdirs() //创建目录,无论是否是父目录都会创建成功
delete() //删除目录
list() //以String类型返回目录下的所有目录和文件名
listFiles() //以File类型的方式返回 目录下 所有的文件和目录。


*/






/*
 * 一  流的分类
 *  1.按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)  
2.按数据流的流向不同分为:输入流,输出流
3.按流的角色的不同分为:节点流,处理流


        二  四个抽像基类
        
        InputStream  OutputStream  Reader   Writer
        
       三  节点流(文件流) 
        FileInputStream
        FileOutputStream
        FileReader
        FileWriter
 */








/*
 * 缓冲流 :效率高
 */
public class IOTest03 {


@Test
public void test() throws Exception{

/*
* BufferedInputStream
*/
//创建流
FileInputStream fis = new FileInputStream(new File("aaa.txt"));
//创建一个缓冲流
BufferedInputStream bis = new BufferedInputStream(fis);

//读取文件
byte[] b = new byte[1024];
int len = 0;
while((len = bis.read(b)) != -1){
System.out.println(new String(b,0,len));
}

//第四步关流 : 先关外面的再关里面的
bis.close();
fis.close();
}

@Test
public void test2(){
long start = System.currentTimeMillis();
String src = "aaa.txt";
String desc = "ddd.txt";
try {
copy2(src, desc);
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}

/*
* 用缓冲流复制文件
*/
public void copy2(String src,String desc) throws Exception{
//第一步创建File对象
File file = new File(src); //读取的文件
File file2 = new File(desc); //复制的文件

//第二步创建流
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);


FileOutputStream fos = new FileOutputStream(file2);
BufferedOutputStream bos = new BufferedOutputStream(fos);


//第三步 一边读一边写
byte[] b = new byte[1024];
int len = 0;
while((len = bis.read(b)) != -1){
bos.write(b, 0, len);
}
//将内存中的内容刷新到文件中。
bos.flush();

//第四步 关流
bos.close();
bis.close();
fos.close();
fis.close();

}

/*
* 用文件流进行文件的复制
*/
public void copy(String src,String desc) throws Exception{
//第一步创建File对象
File file = new File(src); //读取的文件
File file2 = new File(desc); //复制的文件

//第二步创建流
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(file2);

//第三步 一边读一边写
byte[] b = new byte[1024];
int len = 0;
while((len = fis.read(b)) != -1){
fos.write(b, 0, len);
}

//第四步 关流
fos.close();
fis.close();

}
}




/*
* 考虑:字节流和字符流的使用
* 1.字符流用来展示一些文本信息
* 2.字节流一般用来复制文件,复制中文文本是不会出现乱码的
*/






/*
 * 转换流
 * 
 */
import org.junit.Test;
public class InputStreamTest {


/*
* InputStreamReader

* 两个作用:
* 1.可以将字节流转换成字符流
* 2.可以改变文本的编码集- 比如读取文件是gbk那么写出的文件可以转成utf-8
*/




/*
* InputStreamReader(InputStream in, String charsetName)

* charsetName :编码集

* 注意:读取的文件的编码集必须和charsetName编码集格式一致
*/






/*
 * 
 * 
 * 序列化:用ObjectOutputStream类保存基本类型数据或对象的机制
         反序列化:用ObjectInputStream类读取基本类型数据或对象的机制


 */






/*
* 要求:
* 1.需要被序列化对象的类,必须实现Serializable接口。
* 类中的属性除基本类型外也需要实现Serializable接口
* 2.private static final long serialVersionUID;用来表明类的不同版本间的兼容性


*/










/*
* 实现文件内容的插入
*/
@Test
public void test3() throws Exception{
RandomAccessFile raf = new RandomAccessFile("BB.txt", "rw");
//获取指针的位置
long p = raf.getFilePointer();
System.out.println(p);

//seek(int postion) 将指针移到postion的位置
raf.seek(1);

//读完数据后,指针就指向了末尾
String readLine = raf.readLine();

System.out.println(raf.getFilePointer());

System.out.println(readLine);
System.out.println(raf.readLine());

}

/*
* 功能 :在abcdefg 的 b和c的位置插入AAA
*/
@Test
public void test4() throws Exception{
RandomAccessFile raf = new RandomAccessFile("BB.txt", "rw");
//第一步  移动指针到c的位置
raf.seek(2);
//第二步  读取c到最后的数据。注意:指针会移到最后
String str = raf.readLine();
//第三步 指针回移
raf.seek(2);
//第四步 写插入的内容
raf.write("AAA".getBytes());
//第五步 写读取的内容
raf.write(str.getBytes());
//第六步 关流
raf.close();
}

/*
*  功能 :在
*  abcdefg
*  bbb
*  ccc
*  dd
*  的 b和c的位置插入AAA
*/
@Test
public void test5() throws Exception{
RandomAccessFile raf = new RandomAccessFile("BB.txt", "rw");
//第一步  移动指针到c的位置
raf.seek(2);
//第二步  读取c到最后的数据。注意:指针会移到最后
String str = "";
byte[] b = new byte[100];
int len = 0;
while((len = raf.read(b)) != -1){
str += new String(b,0,len);
}

//第三步 指针回移
raf.seek(2);
//第四步 写插入的内容
raf.write("AAA".getBytes());
//第五步 写读取的内容
raf.write(str.getBytes());
//第六步 关流
raf.close();
}
}






/*
 * 程序 : 指的是一段静态的代码
 * 
 * 进程 : 正在运行的程序
 * 
 * 线程:一个进程中包含多个线程。每一个线程可以单独执行一个任务。可以同时开启多个线程。
 * 
 * 问题?何时需要使用多线程?
 * 当我们需要执行两个或两个以上的任务时,就需要我们开启多线程。
 * 
 * 一  如何开启多线程?
 * 第一种继承Thread
 * 第二种实现Runnable接口  详见:ThreadTest02.java
 * 练 习
 * 开启两个线程  一个线程打印100以内的偶数   一个线程打印100以内的奇数
 * 
 * 
 * 二  创建多线程的两种方式的区别?
 * 1.继承Thread
 * 2.实现Runnable接口
 * ①一般会选用实现Runnable接口的方式,因为Java是单继承多实现
 * ②在操作共享数据的时候,Runnable中的数据只有一份。Thread中的数据每个线程拥有一份。
 * ③在调用wait()/notify(),notifyAll()
 * 能在实现Runnable接口的同步方法和同步代码块中  和  继承Thread中的同步代码块中使用
 * 
 * 
 * 
 */




/*
 * 继承Thread实现多线程
 * ①创建一个类并继承Thread
 * ②重写Thread中的run方法
 * ③创建Thread子类的对象
 * ④调用Thread子类对象的start方法
 */




/*
 * ①实现Runnable接口
 * ②重写run方法
 * ③创建Runnable接口实现类的对象
 * ④创建Thread对象并将Runnable实现类的对象作为参数传递给Thread
 * ⑤调用Thread对象的start方法
 */








/*


 * 
 * Thread(String name) : 给线程起名字
 * 
 *  第一波
 *  void start():  启动线程,并执行对象的run()方法
run():  线程在被调度时执行的操作
String getName():  返回线程的名称
void setName(String name):设置该线程名称
static currentThread(): 返回当前线程

第二波
MAX_PRIORITY(10);    
MIN _PRIORITY (1);  
NORM_PRIORITY (5);
涉及的方法:
getPriority() :返回线程优先值 
setPriority(int newPriority) :改变线程的优先级
线程创建时继承父线程的优先级

第三波
static  void  yield():线程让步
暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程
若队列中没有同优先级的线程,忽略此方法
join() :
当某个程序执行流中调用其他线程的 join() 方法时,
调用线程将被阻塞,直到 join() 方法加入的 join 线程执行完为止   低优先级的线程也可以获得执行 
static  void  sleep(long millis):(指定时间:毫秒)
令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排队。
抛出InterruptedException异常
stop(): 强制线程生命期结束
boolean isAlive():返回boolean,判断线程是否还活着


/*
 * 
 * 线程安全问题;
 * 
 * 多个线程卖票可能会出现:错票(0票 负票),重票
 * 
 * 线程安全问题 : 多个线程共同操作一份共享数据的时候就会出现线程安全问题。
 * 
 * 解决线程安全问题方法一:同步代码块
 * 
 * 格式:synchronized(对象(同步锁 、监视器)){
 * 同步代码;
 * }
 * 1.监视器可以是任意类的对象(多个线程必须是同一个对象)。
 * 2.实现Runnable接口的方式 监视器可以使用this
 *     继承Thread的方式监视器不可以使用this
 * 
 * 解决线程安全问题方法二:同步方法
 * 
 * public synchronized void setAge(){
 * 同步代码
 * }
 * 
 * 1.实现Runnable接口 实现的同步方法  监视器默认的是this
 * 2.继承Thread类 实现的同步方法,必须加static。因为原来默认的是this所以不行。
 * 
 * 同步代码块和同步方法中的操作是单线程的,效率低。
 */






/*
 * 
 * 线程安全问题;
 * 
 * 多个线程卖票可能会出现:错票(0票 负票),重票
 * 
 * 线程安全问题 : 多个线程共同操作一份共享数据的时候就会出现线程安全问题。
 * 
 * 解决线程安全问题方法一:同步代码块
 * 
 * 格式:synchronized(对象(同步锁 、监视器)){
 * 同步代码;
 * }
 * 1.监视器可以是任意类的对象(多个线程必须是同一把锁)。
 * 2.实现Runnable接口的方式 监视器可以使用this
 *     继承Thread的方式监视器不可以使用this
 * 
 * 解决线程安全问题方法二:同步方法
 * 
 * public synchronized void setAge(){
 * 同步代码
 * }
//同步方法 - 如果是继承Thread的方式那么同步方法需要加static






/*
 * 死锁:不同的线程分别占用对方需要的同步资源不放弃,
 * 都在等待对方放弃自己需要的同步资源,就形成了线程的死锁


 */
public class DeadLock {


public static void main(String[] args) {


/*
* new Thread(){

* @Override public void run() { for (int i = 0; i <100; i++) {
* System.out.println(Thread.currentThread().getName()); } } }.start();

* new Thread(){

* @Override public void run() { for (int i = 0; i <100; i++) {
* System.out.println(Thread.currentThread().getName()); } } }.start();
*/


StringBuffer s1 = new StringBuffer();

StringBuffer s2 = new StringBuffer();

new Thread() {
public void run() {
synchronized (s1) {
s2.append("A");

try {
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

synchronized (s2) {
s2.append("B");
System.out.print(s1);
System.out.print(s2);
}
}
}
}.start();


new Thread() {
public void run() {
synchronized (s2) {
s2.append("C");

try {
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

synchronized (s1) {
s1.append("D");
System.out.print(s2);
System.out.print(s1);
}
}
}
}.start();


}
}




/*
*  wait():令当前线程挂起并放弃CPU、同步资源,使别的线程可访问并修改共享资源,
*   而当前线程排队等候再次对资源的访问
notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待
  notifyAll ():唤醒正在排队等待资源的所有线程结束等待
 
  上面三个方法实际上是调用的监视器对象的
 
  [面试题]sleep和wait的区别?
  1.sleep睡着的时候会抱着锁   wait睡着的时候会释放锁
  2.sleep是Thread中的方法  wait是Object中的方法
  3.sleep会自动唤醒 wait需要被notify/notifyAll唤醒
*/






/*
 * 单例 : 懒汉  ,饿汉
 *
 *  懒汉 :线程不安全
 */


/*
 * 懒汉 - 使用同步代码块解决线程安全问题
 */
class Bank{
private Bank(){}

private static Bank bank = null;

public static  Bank getInstance(){

if(bank == null){
synchronized (Bank.class) {
if(bank == null){
bank = new Bank();
}
}
}

return bank;
}
}




/*
1.调用Executors 类的静态方法newFixedThreadPool(int nThreads),
创建一个可重用的、具有固定线程数的线程池ExecutorService对象
2.创建Runnable实例,作为线程执行任务
3.调用ExecutorService对象的submit()提交Runnable实例
4.调用ExecutorService对象的shutDown()方法关闭线程池。


 */










/*
* 扩充 (面试题 - Java中的线程池有几种)
// 创建一个缓存线程池
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
//创建一个执行器,使用一个单一的工作线程操作关闭一个无限的队列。
ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
//创建一个线程池,可以调度命令在一个给定的延迟后运行,或周期性地执行。 
ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(20);
*/




/*
 * 开启多线程的第三种方式 : 实现Callable接口 (了解)
 */
public class ThreadTest02 {


public static void main(String[] args) throws Exception, ExecutionException {

//第三步  创建Callable的实现类的对象
MyCall myCall = new MyCall();
//第四步  创建FutureTask对象 并将Callable实现类的对象作为实参传入
FutureTask<Integer> ft = new FutureTask<>(myCall);
//第五步 创建Thread的对象并调用start方法
Thread thread = new Thread(ft);
thread.start();

/*
 * 第一步  实现Callable接口
 * 第二步  重写call方法
 * 第三步  创建Callable的实现类的对象
 * 第四步  创建FutureTask对象 并将Callable实现类的对象作为实参传入
 * 第五步 创建Thread的对象并调用start方法


/*
* 获取属性的详细信息
*/
@Test
public void test(){

Class clazz = Student.class;
//获取本类中所有的属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
// System.out.println(field);
//获取属性的权限修饰符
int modifiers = field.getModifiers();
System.out.print(Modifier.toString(modifiers) + " ");
//获取属性的类型
Class<?> type = field.getType();
System.out.print(type + " ");

String name = field.getName();
System.out.print(name);


System.out.println();
}
}








/*
* 一 Class类
* 1.Class类是反射的源头
* 2.将字节码文件加载到JVM中,我们可以将加载进JVM中的字节码文件理解成Class类的实例
* 3.将JVM中加载进来的字节码文件(Class类的实例)叫做运行时类。


* 二 如何获取Class类
/*
* 反射的作用:给类中私有化的属性赋值 或 调用私有化的方法
*/








/*
* Properties 必须的会
*/
@Test
public void test2() throws Exception{
Properties properties = new Properties();
// FileInputStream fis = new FileInputStream(new File("person.properties"));
/*
* 下边的方式必须会
*/
InputStream fis = this.getClass()
.getClassLoader()
.getResourceAsStream("com/atguigu/java/person.properties");
properties.load(fis);

String name = properties.getProperty("name");
String age = properties.getProperty("age");
System.out.println(name + " " + age);
fis.close();

}
}






public class ProxyXiaoMi implements InvocationHandler {


//目标对象:被代理对象(ITBoss,BigBoss)
private Object target;
/**

* @param target 目标对象:被代理对象(ITBoss,BigBoss)
* @return 返回代理对象的实例
*/
public Object getProxyObject(Object target){
this.target = target;
/*
* 第一个参数 :类加载器
* 第二个参数 : 目标对象实现的所有接口
* 第三个参数 : InvocationHandler实现类的对象
*/
return Proxy.newProxyInstance(
target.getClass().getClassLoader(), 
target.getClass().getInterfaces(), 
this);
}


@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

System.out.println("------------代理开始了-------------");
//调用目标对象的方法
Object obj = method.invoke(target, args);

System.out.println("------------代理结束了-------------");

return obj;
}
}






/*
 * TCP:
 *  1.使用TCP协议前,须先建立TCP连接,形成传输数据通道
2.传输前,采用“三次握手”方式,是可靠的
3.TCP协议进行通信的两个应用进程:客户端、服务端
4.在连接中可进行大数据量的传输
5.传输完毕,需释放已建立的连接,效率低


 */




/*
 *  UDP
1.将数据、源、目的封装成数据包,不需要建立连接
2.每个数据报的大小限制在64K内
3.因无需连接,故是不可靠的
4.发送数据结束时无需释放资源,速度快


 */








一  方法的调用
 *   默认方法的调用 : 实现类的对象.默认方法();
  静态方法的调用: 接口名.静态方法();
  
        二 类优先原则
        1.如果接口中的默认方法和实现类中的方法一样,那么通过实现类的对象优先调用的是实现类中的方法。
        2.如果一个父接口提供一个默认方法,而另一个接口
        也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),
        那么实现类必须覆盖该方法来解决冲突
        3.实现类中重写接口中的默认方法中调用接口中的默认方法 : 接口名.super.方法名()






*
 * 注解的新特性
 * 
 * 1.重复注解 :
 * 举例: @interface b{
 * a[] value();
 * }
 * @Repeatable(value = b.class)
 * @interface a{
 * 
 * }
 * ①创建两个注解 ,一个注解b中含有另一个注解a类性的数组。
 * ②在a注解上加一个元注解Repeatable,value值是另一个注解b.class
 * 2.类型注解
 *    ElementType.TYPE_USE
 *    ElementType.TYPE_PARAMETER
 * 
 */




/*
* Optional : 为了解决空指针异常
*/
@Test
public void test(){
//创建一个空的对象
Optional<Object> empty = Optional.empty();

/*
* of(Object obj)将obj放入到Optional容器中
*/
Optional<String> of = Optional.of("ccc");
//获取容器中的数据
System.out.println(of.get());

/*
* 这种方式还是会发生空指针-所以不常用
Optional<Object> of2 = Optional.of(null);
System.out.println(of2.get());
*/

/*
* 类似于  if-else  如果 “aaa”为空那么就会输出"ccc"
* 如果"aaa"不为空那么就输出"aaa"
*/
Optional<Object> ofNullable = Optional.ofNullable("aaa");
Object orElse = ofNullable.orElse("ccc");
System.out.println(orElse);
}

/*
* isPresent() - 当前Optional容器中是否有数据,如果有返回true,如果没有返回false
*/
@Test
public void test2(){

Optional<Object> optional = Optional.ofNullable(null);

if(optional.isPresent()){
System.out.println("有数据");
System.out.println(optional.get());
}else{
System.out.println("没有数据");
Object orElse = optional.orElse("我是默认值");
System.out.println(orElse);
}
}
}


/*
 * 构造器引用
 * 
 * 格式 :ClassName :: new
 * 
 * 说明:
 *  1.构造器参数列表要与接口中抽象方法的参数列表一致!
 *  2.且方法的返回值即为构造器对应类的对象。


 */




/*
 * 
 * 一  lambda表达式 就是为了替换匿名内部类
 * 
 * 二  Lambda操作符(箭头操作符)  -> 
 * 
 *  左侧:指定了 Lambda 表达式需要的参数列表
右侧:指定了 Lambda 体,是抽象方法的实现逻辑,也即 Lambda 表达式要执行的功能。


       三  函数式接口 - 接口中只有一个抽像方法
       1.只有函数式接口才可以使用lambda表达式
       2.函数式接口可以使用@FunctionalInterface进行注解来验证是否是函数式接口






/*
 1.当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
 
 2.方法引用就是Lambda表达式,就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。


 3.要求:实现抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!


 4.方法引用:使用操作符 “::” 将类(或对象) 与 方法名分隔开来。


 5.如下三种主要使用情况:
 
  对象::实例方法名
类::静态方法名
类::实例方法名






一 注意:
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行

         二1- 创建 Stream
一个数据源(如:集合、数组),获取一个流
2- 中间操作
一个中间操作链,对数据源的数据进行处理
3- 终止操作(终端操作)
一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值