javaSE学习总结,javase总结
分享于 点击 8880 次 点评:163
javaSE学习总结,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- 终止操作(终端操作)
一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用
相关文章
- 暂无相关文章
用户点评