java进阶(二)-java小干货
java一些精干知识点分享
- 2. java小干货
- 2.1循环遍历
- 2.2可变参数
- 2.3 list和数组转化
- 2.3.1 数组转list
- 2.3.2 list转数组
- 2.4 值传递和地址传递
- 2.4.1值传递
- 2.4.2 地址传递
- 2.4.3易错点总结
- 2.5 数据类型
- 2.5.1基础知识
- 2.5.2 基础数据和包装类
- 2.6 字符串
- 2.6.1 char/String区别
- 2.6.2 .关于String的创建方式
- 2.6.3 String StringBuffer StringBuild区别
- 2.7数组
- 2.7.1 数组定义
- 2.7.2 数组帮助类Arrays
- 2.7.3 Apache Commons Lang3
- 2.8 equals和==、compareTo区别
- 2.8.1 ==和equals
- 2.8.2 compareTo
- 2.9代码块、内部类和匿名类
- 2.9.1代码块
- 2.9.2内部类
- 2.9.3匿名类
- 2.10枚举
- 2.11 集合
- 2.12 日期类LocalDate
- 2.13 java泛型及通配符
- 2.14文件流IO
2. java小干货
2.1循环遍历
数组、list、map都需要遍历循环,有下面集中循环方式
1.for ecah
list可以是一个数组、list、set
// list可以是一个数组、list、set
for(bject o :list) {}
2.Iterator迭代器
list可以是list、set类的子类
Iterator iter = list.iterator();while(iter.hasNext()){Object o = iter.next();}
3.loop with size
可以是数组、list能得到索引长度的类及子类
for(int i=0;i<list.size();i++){Object o= list.get(i);}
4.lambda表达式
list.forEach((value)->{System.out.println(value);});
代码示例
public class GanHuo {@Testpublic void t1(){//1.for-each遍历,最简单,但无法获得索引System.out.println("=======for(Object:list)循环=========");String arrayStr[]=new String[]{"1","2","3"};//1-1 数组System.out.println("for-each遍历数组-----------");for (String s : arrayStr) {System.out.println("arrayStr:"+s);}//1-2 listList<Integer> list= Arrays.asList(1,2,3,4);System.out.println("for-each遍历list-----------");for (Integer i : list) {System.out.println("list:"+i);}//1-3 遍历mapMap<String,String> map=new HashMap<>();System.out.println("for-each遍历Map-----------");map.put("1", "111");map.put("2", "222");map.put("3", "222");//得到key的collectonSet<String> keySet=map.keySet();for(String key:keySet){System.out.println("map["+key+"]="+map.get(key));}}@Testpublic void t2(){System.out.println("=======Iterator循环================");//1-2 listList<Integer> list= Arrays.asList(1,2,3,4);System.out.println("Iterator 遍历list-----------");Iterator iter=list.iterator();while (iter.hasNext()) {System.out.println("list:"+iter.next());}//1-3 遍历mapMap<String,String> map=new HashMap<>();System.out.println("Iterator 遍历Map-----------");map.put("1", "111");map.put("2", "222");map.put("3", "222");//得到key的collectonSet<String> keySet=map.keySet();iter=keySet.iterator();while (iter.hasNext()) {String key= (String) iter.next();System.out.println("map["+key+"]="+map.get(key));}}@Testpublic void t3(){System.out.println("=======for。size循环================");//1-1 数组String arrayStr[]=new String[]{"1","2","3"};System.out.println("loop size 遍历数组-----------");for (int i = 0; i < arrayStr.length; i++) {System.out.println("arrayStr["+i+"]="+arrayStr[i]);}//1-2 listList<Integer> list= Arrays.asList(1,2,3,4);System.out.println("loop size 遍历list-----------");for (int i = 0; i < list.size(); i++) {System.out.println("list["+i+"]="+list.get(i));}}@Testpublic void t4(){System.out.println("=======lambda表达式================");//list的lambda表达式List<Integer> list= Arrays.asList(1,2,3,4);System.out.println("lambda表达式 遍历list-----------");list.forEach((value)->{System.out.println(value);});//Map的lambda表达式Map<String,String> map=new HashMap<>();System.out.println("lambda表达式 遍历Map-----------");map.put("1", "111");map.put("2", "222");map.put("3", "222");map.forEach((key, value)->{System.out.print("key = " + key);System.out.println(", value = " + value);});}}
2.2可变参数
可变参数是指不指定参数的个数
定义:
数据类型… 变量名
可变参数规范
1.可变参数本身是一个数组
2.可变参数也可传递一个数组
3.可变参数个数不受限制,可无限制,也可没有
4.如果可变参数和常规参数混合,则可变参数要放到最后
5.每个方法最多只能有一个可变参数
代码示例
public class ChangeParam {public void param(Integer... val){System.out.println("val包含:"+val.length+"个参数");for (Integer i : val) {System.out.println(i);}}/***如果一个方法里包含常规参数和可变参数,则可变参数必须放置到最后一个*/public void param1(String name,Integer age,String... likes){System.out.println("name:"+name);System.out.println("age:"+age);System.out.println("likes-----");String temp="";for (String like : likes) {temp+=like+",";}System.out.println(temp);}@Testpublic void t1(){//可以传递不受限制的个数param(1,2,3);//可以不传参数param();//也可传递数组Integer[] array={1,2,3};param(array);//常规和可变参数混合param1("蒋增奎",20,"火锅","串串","烤鸭");}
}
2.3 list和数组转化
2.3.1 数组转list
1.使用List=Arrays.asList(数组对象),最简单,但不能新增删除
2.List=new ArrayList<>(Arrays.asList(intArray)),可新增删除,但性能差
3. Collections.addAll(list对象, 数组对象);可新增删除,性能好
4.list= Stream.of(数组对象).collect(Collectors.toList());
@Testpublic void array2List(){System.out.println("=========Arrays.asList=======");//1---直接用Arrays.asList后不能再新增System.out.println("1---直接用Arrays.asList后不能再新增");//基本类型数组Integer[] intArray={1,2,3};List<Object> list1= Arrays.asList(intArray);// list1.add(4); //不能再新增,否则要报异常printList(list1);//自定义数组TestVO[] objArray={new TestVO(1,"jzk"),new TestVO(2,"张三")};list1=Arrays.asList(objArray);printList(list1);//2--Arrays.asList作为构造参数传入,可新增,但性能差System.out.println("2--Arrays.asList作为构造参数传入,可新增,但性能差");list1=new ArrayList<>(Arrays.asList(intArray));list1.add(4);printList(list1);//3--Collections.addAll(list,数组);能新增删除,性能好System.out.println("3--Collections.addAll(list,数组);能新增删除,性能好");list1=new ArrayList<>();Collections.addAll(list1, intArray);list1.add(4);printList(list1);//4--使用 Stream;能新增删除,性能好System.out.println("4--使用 Stream;能新增删除,性能好");list1= Stream.of(intArray).collect(Collectors.toList());list1.add(4);printList(list1);}private void printList(List<Object> list){for (Object o : list) {System.out.println(o);}}
2.3.2 list转数组
核心用到list.toArray()方法
1.Object[] arrays=list.toArray(); 只能获得Object数组
2.对象数组=list.toArray(new 对象[list.size] ) ;//可以获得对应的对象数组
测试代码
@Testpublic void list2array(){List<TestVO> list=getTestVO();System.out.println("方法1:list.toArray()===========");//注意:只能用转换成Object[]数组,不能强制转化Object[] arrays=list.toArray();for (Object array : arrays) {System.out.println((TestVO)array);}System.out.println("方法2:list.toArray(数组对象)===========");//这样可获得实际的类TestVO[] vos=new TestVO[list.size()];list.toArray(vos );for (TestVO vo : vos) {System.out.println(vo);}//或者这样写System.out.println("方法3:list.toArray(数组对象)简写===========");vos=list.toArray(new TestVO[list.size()]);for (TestVO vo : vos) {System.out.println(vo);}System.out.println("方法4:String[] strings = list.stream().toArray(String[]::new);===");TestVO[] vos2=list.stream().toArray( TestVO[]::new);for (TestVO vo : vos2) {System.out.println(vo);}}private void printList(List<Object> list){for (Object o : list) {System.out.println(o);}}private List<TestVO> getTestVO(){List<TestVO> list=new ArrayList<>();list.add(new TestVO(1,"jzk"));list.add(new TestVO(2,"张三"));return list;}
2.4 值传递和地址传递
在学习 Java 编程语言的过程中,我们经常会听到“值传递”和“地址传递”这两个概念。它们是用来描述参数传递方式的术语,而理解它们的区别对于编写高效的代码非常重要。在本文中,我们将详细介绍这两种传递方式,并通过代码示例来说明它们的差异。
2.4.1值传递
在 Java 中,基本数据类型(如整数、布尔值等)都是以值传递的方式进行参数传递。这意味着当我们将一个基本数据类型作为参数传递给一个方法时,方法内部会创建一个新的变量来存储这个参数的值,而不会影响原始的变量。
执行过程
- 首先,在调用方法时,将实际参数的值复制一份,并将这份副本传递给方法进行操作。
- 在方法内部,这个副本的值被赋给一个新的局部变量。
- 在方法执行过程中,对该局部变量的任何改动都不会影响原始的变量,因为它们指向的是不同的内存空间。
- 当方法执行完毕后,这个局部变量和方法的栈帧都会被销毁,而原始的变量的值保持不变。
基本数据类型的传递过程中,传入的值被复制到方法内部,并在方法内部进行操作,但不会影响原始变量的值。
@Testpublic void valPass(){String str="a";double db= Double.parseDouble("34.5");Double db1=45.2;Integer zs=Integer.valueOf(100);int zs1=200;boolean b=false;Boolean b1= true;System.out.println("str="+str);System.out.println("db="+db);System.out.println("db1="+db1);System.out.println("zs="+zs);System.out.println("zs1="+zs1);System.out.println("b="+b);System.out.println("b1="+b1);change1(str,db,db1,zs,zs1);System.out.println("str="+str);System.out.println("db="+db);System.out.println("db1="+db1);System.out.println("zs="+zs);System.out.println("zs1="+zs1);}private void change1(String str,double db,Double db1,int zs,Integer zs1){System.out.println("============change==========");str="b";db=-45.2;db1=-22.4;zs=-1;zs1=-2;}
执行效果,可以看出这些都是值传递,被引用后并没有改变以前值:
str=a
db=34.5
db1=45.2
zs=100
zs1=200
b=false
b1=true
============change==========
str=a
db=34.5
db1=45.2
zs=100
zs1=200
2.4.2 地址传递
与基本数据类型不同,Java 中的对象类型(如数组、集合、自定义类等)则是以地址传递的方式进行参数传递。这意味着当我们将一个对象作为参数传递给一个方法时,方法内部使用的是这个对象的引用,而不是对象本身。
执行过程
-
创建一个对象并将其引用赋值给一个变量。
-
将这个变量作为参数传递给一个方法。
-
在方法内部,参数变量接收到了对原始对象的引用。
-
在方法内部修改参数变量所指向的对象时,原始对象也会受到影响。
-
方法执行完毕后,返回到原始调用处,可以通过原始变量访问到被修改后的对象。
对象的引用传递意味着传递的是对象的引用,通过引用可以访问和修改原始对象的属性。
测试代码:
@Testpublic void addressPass(){StringBuffer sb=new StringBuffer("aa");TestVO vo=new TestVO(1,"蒋增奎");String[] array={"1","2","3"};List<Integer> list=new ArrayList<>();list.add(1);list.add(2);Map<String,Integer> map=new HashMap<>();map.put("1", 11);map.put("2", 22);System.out.println("sb:"+sb);System.out.println("vo:"+vo);System.out.println("array:"+ Arrays.toString(array));System.out.println("list:"+Arrays.toString(list.toArray()));System.out.println("map:"+map.toString());System.out.println("================");change2(sb,vo,array,list,map);System.out.println("sb:"+sb);System.out.println("vo:"+vo);System.out.println("array:"+ Arrays.toString(array));System.out.println("list:"+Arrays.toString(list.toArray()));System.out.println("map:"+map.toString());}private void change2( StringBuffer sb, TestVO vo,String[] array,List<Integer> list,Map<String,Integer> map){sb.append("dd");vo.setName("蒋大爷");array[0]="改值11";list.add(3);map.put("3",333);}
效果,地址引用值都会被改变
sb:aa
vo:TestVO(id=1, name=蒋增奎)
array:[1, 2, 3]
list:[1, 2]
map:{1=11, 2=22}
================
sb:aadd
vo:TestVO(id=1, name=蒋大爷)
array:[改值11, 2, 3]
list:[1, 2, 3]
map:{1=11, 2=22, 3=333}
代码2:
@Testpublic void t2() {TestVO vo1=new TestVO(1, "jzk");TestVO vo2=vo1;vo2.setName("奎哥");System.out.println(vo1); //打印TestVO(id=1, name=奎哥),不是jzkSystem.out.println(vo2);//TestVO(id=1, name=奎哥)}
首先创建一个对象TestVO vo1,接着申请另一款空间,用来创建TestVO vo2,且vo2=vo1,说明两个数组都指向同一块空间,修改vo2中的字段也就相当于修改了vo1中对应的元素。
代码3
@Testpublic void t1(){TestVO vo=new TestVO(1, "jzk");System.out.println(vo);change3(vo);System.out.println(vo);change4(vo);System.out.println(vo);}private void change3(TestVO vo){TestVO vo1=vo; //把vo赋值给vo1,两个对象是指向同一个地址vo1.setName("奎哥");}private void change4(TestVO vo){vo.setName("鸡哥");}
打印效果:
TestVO(id=1, name=jzk)
TestVO(id=1, name=奎哥)
TestVO(id=1, name=鸡哥)
代码说明:
change3()和change4()效果一样,change3()虽然通过了赋值,但两个对象指向的同一个地址
2.4.3易错点总结
易错点
java对象:String ,int等对应的封装类Integer,java.util.Date,BigDecimal是值传递,不是地址传递,虽然他们是对象
值传递VS地址传递

2.5 数据类型
2.5.1基础知识
Java基本类型共有八种,基本类型可以分为三类,字符类型char,布尔类型boolean以及数值类型byte、short、int、long、float、double。数值类型又可以分为整数类型byte、short、int、long和浮点数类型float、double。JAVA中的数值类型不存在无符号的,它们的取值范围是固定的,不会随着机器硬件环境或者操作系统的改变而改变。实际上,JAVA中还存在另外一种基本类型void,它也有对应的包装类 java.lang.Void,不过我们无法直接对它们进行操作


代码说明
//基础数据类型@Testpublic void t1(){//1.整数类型byte b=100;short s=10000;int i=1000000000;//注意:长整型long要加L后缀,才能最大化long l=900000000000000000L;System.out.println("byte:"+b);System.out.println("short:"+s);System.out.println("int:"+i);System.out.println("long:"+l);//2.浮点型//注意:小数默认是double,如果要用float,需要再数字后面加f或者Ffloat f=34.67f;double d=34.67;//char类型,char必须用单引号包围,只能一个字符char c1='A';char c2='2';//booleanboolean b1=false;}
注意事项:
1.整数:short int long 就是取值范围不一样,对计算没有影响,当然计算性能存储越低性能越高,long后面需要增加L/l后缀
2.浮点型:小数默认为double类型,float要加l/L后缀,double计算精度高,但性能差些,但高精度计算用BigDecmal(小数存在计算精度问题)
3.基础类型不能赋null,只有对应包装类才行
默认值和初始化
每一种类型都有一个默认值,除基本类型外,其他的类型的默认值都是 null,因为它们都是引用类型。整数默认为 int 类型,浮点数默认为 double 类型。

代码
public float f;public double d;public boolean b;private int i;private Boolean b3;@Testpublic void t2(){//静态方法有默认值System.out.println(f); //0System.out.println(d); //0System.out.println(i); //0System.out.println(b); //falseSystem.out.println(b3); //nullboolean b1;System.out.println(b1); //编译不通过}
注意事项:
1.只有为class的字段属性声明才有默认值
2.在方法内声明的变量,如果不赋初始值,编译不通过
2.5.2 基础数据和包装类
Java 是面向对象的语言,但是为了便于开发者的使用,Java 中却沿用了 C 语言的基本数据类型,在进行基本的数据计算时,开发者可以直接使用基础类。但是基本数据类型是不具备对象的特征的,不能调用方法,而且基本数据类型不能存入集合中,所以就需要将基础数据类型实例封装为 Java 对象,使其具有了对象的属性和方法。

基础类型和包装类的区别
-
存储位置不同:
基本数据类型直接将值放在栈中;
包装类型是把对象放在堆中,然后通过对象的引用来调用他们 ; -
初始值不同:
int的初始值为 0 、 boolean的初始值为false ;
包装类型的初始值为null ; -
使用方式不同:
基本数据类型直接赋值使用就好;
在集合如 coolectionMap 中只能使用包装类型;
在应用场景中MVC模式的form-vo,Dto,PO对象的属性最好都用包装类,因为基础类型都有默认值0或者false,在实际应用中,null和0,false是有实际意义的 -
包装类是java对象,封装有相关方法,而基础类型没有
比如:Integer.valueOf()等
为什么还要保留基础类型?
- 在 Java 中,使用 new 关键字创建的对象存储在堆中,并且通过栈中的引用来使用这些对象,所以对象本身来说是比较消耗资源的。
- 基本类型存储在栈里,因为栈的效率高,所以保留了基本类型。变量的值存储在栈中,方法执行时创建,结束时销毁,因此更加高效。
- 使用基本数据类型参与计算时的性能要比使用包装类的高。
基础类型之间的转换
(1)基础类型自动转化
1.范围小的类型可以自动转换成范围大的类型。
2.整型可以自动转换成浮点型
3.反之,范围大的转化为范围小的必须强制转换
4.范围:short->int->long->float->double ,从小到大
示例代码:
@Testpublic void t3(){System.out.println("1.自动转换===========");byte i1=2;short i2=i1;int i3=i2;long i4=i3;float f1=3.45f;double f2=f1;float f3=i3;double f4=i4;}
(2)强制执行
范围大的转化为范围小的,必须用强制转换
范围大的类型需要强制转换成范围小的类型,否则会精度丢失。
强制类型转换可能会导致数据溢出或者产生负数。
范围小到范围大的的转换也可以用强制转化,和自动转换效果一样
@Testpublic void t4(){System.out.println("2.强制转换===========");double f1=34.56565;float f2=(float) f1;int i=(int)f1;System.out.println(i);//范围小的转换也可以用强制转化,和自动转换效果一样int i1=34;float f3=(float)i1; }
基本类型和包装类的转换
基本类型与包装类之间的转换需要使用到自动装箱和拆箱的操作。
@Testpublic void t5(){System.out.println("3.基本类型和封装类转换===========");int i=10;Integer i1=i; //自动装箱Integer i2=30;int i3=i2;//自动拆箱}
包装类的常用方法
1.包装类对象=包装类.valueOf(对应的基础类型);
2.基础数据类型/包装类对象=包装类.parseXXX(字符串) ;字符串转化成数据类型
@Testpublic void t6() {System.out.println("4.包装类的常用方法===========");Integer i = Integer.valueOf(2);int i1 = Integer.parseInt("344"); //字符串转成整数Integer i2 = Integer.parseInt("34444"); //实际是转化成int,int在装箱成IntegerSystem.out.println(i);System.out.println(i1);System.out.println(i2);}
2.6 字符串
2.6.1 char/String区别
1.char和String的区别
char是字符类型,是基础数据类型,长度固定,用单引号表示 如 c=‘谢’;
String是字符串类型,不是基础数据类型,长度无法确定,用双引号表示 str=“傻啊”。
关于String类。
(1)、String类时final类,所以是不可继承的;
( 2)、String类是的本质是字符数组char[];
( 3)、Java运行时会维护一个String Pool(String池),JavaDoc翻译很模糊“字符串缓冲区”。String池用来存放运行时中产 生的各种字符串,并且池中的字符串的内容不重复。而一般对象不存在这个缓冲池,并且创建的对象仅仅存在于方法的堆 栈区。
4.String虽然是对象,但传参也是值传递,不是地址传递
@Testpublic void t7() {String s="abc";Character c='中';char[] cs= s.toCharArray();for (char c1 : cs) {System.out.println(c1);}char[] cs2={'天','地','人'};String s1=new String(cs2);System.out.println(s1);}
2.6.2 .关于String的创建方式
字符串有两种创建方式,String s1=“a”; String s=new String(“a”)其逻辑是不一样的
1.直接创建 String str1 = “123”
直接创建的 String 类的数据存储在公共的常量池中(Java 的常量优化机制),即直接创建的相同值的不同 String 类的引用相同。
2.new 创建 String str1 =new String(“123”)
通过 new 关键字创建的 String 和其他一般的类的创建一样,数据是存储在 String 类的对象的堆上,即通过 new 关键字创建的相同值的不同 String 类的引用不同。
String str1 = "Java";
String str2 = "Java";
String str3 = str2 + "";
String str4=new String("Java");
String str5=new String("Java");
String str6=str1;
String str7=str4
System.out.println(str1 == str2); // Output: true
System.out.println(str2 == str3); // Output: false
System.out.println(str4== str5); // Output: false
System.out.println(str1== str5); // Output: false
System.out.println(str1== str6); // Output: true
System.out.println(str4== str7); // Output: true

代码说明:
-
(str1 == str2)== true
直接创建String,其实就是放到常量池里的对象,直接创建时,先去常量池寻找,如果有,则引用,所以这两个时一个东西 -
(str2 == str3)==false
str3 = str2 + “”;代码实际上是创建了一个StringBuild对象,已经是两个对象了 -
(str4 == str4)==false
两个字符串都是new String(“Java”),是两个对象,所以为false
2.6.3 String StringBuffer StringBuild区别
1.字符串String
字符串类是final修饰,不可继承和修改的,
String s="a";
s=s+"b";
其实是产生了两个字符串,执行s=s+“b”;后,s="a"就被丢弃在公共常量池里,如果进行大量的修改,
会导致性能很差。
2.字符串StringBuffer
在 Java1.0 的时候,若要对字符串进行大量修改,应当使用 StringBuffer,它是可修改的,同时,当时的开发人员考虑到多个线程对一个字符串的修改可能出现线程不安全的问题,于是让 StringBuffer 在拥有可修改字符串的功能的情况下,又给它加上了线程安全的机制。看到这里是不是觉得还挺好,挺正常的?但是要知道一个前提,那就是在 Java5 之前的 Java 在处理字符串的速度上一直被别人诟病,原因出在哪里?原因就在于这个 StringBuffer 上面。
StringBuffer 本来是为了实现大量修改字符串的功能而出现的,但却因为 Java 的开发人员给它加了个线程安全的功能,导致它执行效率极大地下降。这个线程安全的功能的实现并不是像我们现在用的方法,当时只是保证没有异常抛出,程序可以正常运行下去而已。在 Java 中,要实现字符串的相加,用加法运算符将两个字符串相加即可。但在这个过程中,Java5 之前是有 String 自动隐含地转换成 StringBuffer,再进行操作这一个步骤的(毕竟 String 类不可直接修改)。只要有这些步骤,就可以实现字符串的修改,但是呢,StringBuffer 有个线程安全的功能,它会在上面提到的步骤中还额外的执行一些功能,以保证线程的安全,而且,这里实现线程安全的方式和我们现在用锁的方式是不一样的!它这里的实现线程安全的方式极为繁琐且复杂,这就大大降低了 StringBuffer 的执行效率,以至于后来被广大程序员诟病。
3.字符串StringBuilder
我们仔细地想一下,实际上也并没有多少地方需要在修改字符串的同时保证线程安全,就算有,我们给它加个锁就行。基于这种想法,在 StringBuffer 出现 10 年之后,Java 的开发人员回过头看这个问题,才发现 StringBuffer 的实现是多么的愚蠢,于是后来在 Java5 就有了 StringBuilder。StringBuilder 同样可以快速高效地修改字符串,同时不是线程安全的。虽然它不是线程安全的,但是它的执行效率却比 StringBuffer 要高上了不少。在 Java5 之后的版本中,字符串相加隐含的转化过程中,不再将 String 转化为 StringBuffer,而是转化成 StringBuilder。
总结:
在大量操作字符串时,java已经优化了,不推荐使用StringBuffer
2.7数组
2.7.1 数组定义
数组有多种定义方式
@Testpublic void t1() {//第一种定义数组的方法:int[] array1 = {1, 2, 3};//直接赋值(静态初始化)//int[]是数组的类型,array为数组名,随意取名字//第二种定义数组的方法:int[] array2 = new int[]{1, 2, 3, 4};//数组的动态初始化//第三种定义数组的方法:int[] array3 = new int[10];//只是分配了内存,但是没有进行赋值,默认值都是0,System.out.println(array3[2]); //0//第四种定义数组的方法:int[] array4;array4 = new int[]{1, 2, 3};//一定要为数组符初值,不然编译器会报错,int[] array5=null;//等价int[] array4}
4.注意事项
- 静态初始化虽然没有指定数组的长度,编译器在编译时会根据{}中元素个数来确定数组的长度。
- 静态初始化时, {}中数据类型必须与[]前数据类型一致。
- 静态初始化可以简写,省去后面的new T[]。T可以为任意数据类型。
- 如果数组中存储元素类型为引用类型,默认值为null。
- 初始化后,数组的长度是固定的,不能动态扩容,这个是和list最大的区别
- 数组参数是地址引用,不是值引用
地址引用:
int[] array1 = {1,2,3,4};
System.out.print(Arrays.toString(array1));//打印[1,2,3,4]int[] array2 = array1;
array2[1] = 99;
System.out.print(Arrays.toString(array1));//打印[1,99,3,4],不是[1,2,3,4]
System.out.print(Arrays.toString(array2));//打印[1,99,3,4]
首先创建一个数组array1,并初始化赋值为1,2,3,4,然后打印数组array1,接着申请另一款空间,用来创建array2,且array2=array1,说明两个数组都指向同一块空间,修改array2中的第二个元素也就相当于修改了array1中对应的元素。
2.7.2 数组帮助类Arrays
Arrays提供了几个很有用的数组帮助方法:
| 方法 | 说明 |
|---|---|
| toString | 把数组转化为字符串 |
| sort | 数组元素排序 |
| binarySearch | 查找元素在数组中的位置索引 |
| asList | 把数组转化成list |
直接看代码,一目了然
@Testpublic void t3(){System.out.println("Arrays类的常见用法");int[] array={5,4,2,6,3};//1.打印String str=Arrays.toString(array);System.out.println(str);//[5, 4, 2, 6, 3]//2.数组大小排序Arrays.sort(array);System.out.println(Arrays.toString(array));//[2, 3, 4, 5, 6]//3.判断两个数组内容是否相等int[] array1={1,2,3};int[] array2={1,2,3};System.out.println(Arrays.equals(array1, array2)); //trueSystem.out.println(array1.equals(array2));//false,不能采用这个方法判断数组内容//3.查找某个元素的索引int[] array3={1,2,3};int index=Arrays.binarySearch(array3,2);System.out.println(index); //1//注意事项,如果没有,则返回小于0,如果多个,则返回第一个int[] array4={1,2,3,2};System.out.println(Arrays.binarySearch(array4, 2));//1System.out.println("ddd:"+Arrays.binarySearch(array4, 4));//小于零//4.转化成list数据类型Integer[] array5={1,2,3};//如果是对象,则直接List<对应的数组元素类型>List<Integer> list=Arrays.asList(array5);for (Integer i : list) {System.out.println(i);}// list.add(9); //运行报错,不能新增和删除// list.remove(0);//运行报错,不能新增和删除/***注意如果数组是基本数据类型,用Array.asList是无法转化的。需要借助第三方先把基本类型数组转化成对应的包装类数组如:Apache Commons Lang3*/int[] array6={1,2,3,5};Integer[] array7= ArrayUtils.toObject(array6);//4.copy值int[] arr1 = {1, 2, 3};int[] arr2 = Arrays.copyOf(arr1, 5);System.out.println(Arrays.toString(arr2)); //[1, 2, 3, 0, 0]//注意:copyOf是值copy,不是地址引用arr2[3]=20;System.out.println(Arrays.toString(arr2));//[1, 2, 3, 20, 0]System.out.println(Arrays.toString(arr1));//[1, 2, 3]//copyOfRange方法提供了开始索引int[] arr3 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};int[] arr4 = new int[5];arr4 = Arrays.copyOfRange(arr3,3,5);System.out.println(Arrays.toString(arr4));//[4, 5]}
2.7.3 Apache Commons Lang3
org.apache.commons.lang3.ArrayUtils这个类也很大扩展了数组的操作,具体查看apache文档
2.8 equals和==、compareTo区别
2.8.1 ==和equals
- == 是一个运算符,用于比较两个对象的引用是否相同,即它们是否指向内存中的相同位置。
- equals 是一个方法,通常在Object类中定义,它用于比较两个对象的内容是否相等。默认情况下,equals方法执行与==相同的引用比较,但它可以被子类重写以提供自定义的相等性逻辑
“== ”在哪些情况下比较的是对象内容而不是引用
- 在Java中,== 运算符通常比较的是对象的引用。但在以下情况下,== 可以比较对象的内容而不是引用:
- 对于基本数据类型(如int、char等),== 比较的是它们的值,而不是引用。
- 字符串常量池:对于字符串字面值,就是String s=“123”,不是String s=new String(“123”);,Java使用常量池来存储它们,因此相同的字符串字面值使用==比较通常会返回true。
代码1
@Testpublic void t1(){//基本类型数据(数值、字符、布尔)的值一样,则==为truechar c1='a';char c2='a';float f1=3.5f;float f2=3.5f;double f3=3.5;int i1=1;int i2=1;long i3=1l;System.out.println(c1==c2);//trueSystem.out.println(f1==f2);//trueSystem.out.println(f1==f3);//trueSystem.out.println(i1==i2);//trueSystem.out.println(i1==i3);//true}
代码2: 字符串是一个对象又有基础数据的特殊性,可参考2.6.2
@Testpublic void t2(){String s1="123";String s2="123";String s3=s1;String s4=s2+"";String s5=new String("123");String s6=new String("123");String s7=s5;//s="xx"是直接声明,String是final常量,性质和基础数据类型一样,s1,s2都指向同一个内存地址System.out.println(s1==s2); //true//所有=变量赋值的语法,指针都是一样System.out.println(s1==s3); //true//因为String是final类型,s2+""实际是创建一个对象System.out.println(s1==s4); //false//两个不同对象,内存地址不一样System.out.println(s5==s6); //false//所有=变量赋值的语法,指针都是一样System.out.println(s5==s7); //true//如果是euqal比较,这几个都返回trueSystem.out.println( //trues1.equals(s2) && s1.equals(s3) && s1.equals(s4) && s5.equals(s6));}
}
代码3:标准vo对象
@Testpublic void t3(){TestVO vo1=new TestVO(1,"jzk");TestVO vo2=vo1;TestVO vo3=new TestVO(1,"jzk");//内存指针一样System.out.println(vo1==vo2);//true//两个不同对象System.out.println(vo1==vo3);//false//三个对象值都是一样的System.out.println(vo1.equals(vo2) && vo2.equals(vo3));//true//vo2修改了值,因为vo1指针和他一致,所以vo1也会改变,最后他们都是一致的vo2.setName("奎哥");System.out.println(vo1==vo2);//true//值已经改变了System.out.println(vo3.equals(vo1));//false}
equals 和 hashCode 之间有什么关系?
equals 和 hashCode 在Java中通常一起使用,以维护对象在散列集合(如HashMap和HashSet)中的正确行为。
如果两个对象相等(根据equals方法的定义),那么它们的hashCode值应该相同。
也就是说,如果重写了一个类的equals方法,通常也需要重写hashCode方法,以便它们保持一致。
这是因为散列集合使用对象的hashCode值来确定它们在内部存储结构中的位置。
2.8.2 compareTo
obj.compareTo(object otherstr);
仅仅知道两个字符串是否相同是不够的。对于排序应用来说,必须知道一个字符串是大于、等于还是小于另一个。一个字符串小于另一个指的是它在字典中先出现。而一个字符串大于另一个指的是它在字典中后出现。字符串(String)的 compareTo() 方法实现了这种功能。
- compareTo() 方法用于按字典顺序比较两个字符串的大小,该比较是基于字符串各个字符的 Unicode 值。
- 如果两个字符串调用 equals() 方法返回 true,那么调用 compareTo() 方法会返回 0,如果前者大则大于0,否则小于0
- compareTo只能用于对象,不能用于基础数据类型,他实际上是Comparable接口类的方法,实现这个接口的有:String、基础数据类型的包装类、Date、BigDecimal 等
代码:
@Testpublic void t4(){//字符串比较String s1="a";String s2="abc";System.out.println(s1.compareTo(s2));//基本类型的包装类比较Integer i1=3;Integer i2=5;System.out.println(i1.compareTo(i2));//<0System.out.println(i1<i2);//true//日期Date,BigDecimalDate d1= DateUtil.getDateByStr("2003-10-01", DateUtil.date_gs);Date d2= DateUtil.getDateByStr("2004-09-01", DateUtil.date_gs);System.out.println(d1.compareTo(d2));//<0BigDecimal bg1=new BigDecimal("1.0");BigDecimal bg2=new BigDecimal("1.00");System.out.println(bg1.equals(bg2)); //返回的是false,所以比较BigDecimal不要用equalsSystem.out.println(bg1.compareTo(bg2));//0}
}
2.9代码块、内部类和匿名类
2.9.1代码块
1.定义:
类里用{}包裹起来的代码称为代码块,代码块有三种类型
1.静态代码块
用static关键字修饰叫静态代码块,
2.同步代码块
使用synchronize关键字修饰,并使用"{}“括起来的代码片段.它表示在同一时间只能有一个线程进入到该方法块中,是一种多线程保护机制.
3.非静态代码块
在类中没与任何的前缀或后缀,并使用”{}"括起来的代码片段叫非静态代码块,也叫构造代码块
//非静态代码块{int i=0;System.out.println("非静态代码块........");}//静态代码块static {int i1=0;System.out.println("静态代码块........");}
静态代码块特点
- 静态代码块使用static关键字进行修饰
- 静态代码块的内部可以有输出语句
- 静态代码块在类加载时执行,并且只会执行一次(因为一个类只会加载一次)
- 静态代码块用于初始化类,但是初始化的是类的静态属性,类的非静态属性是无法在静态代码块中被初始化的
- 若是在一个类中存在多个静态代码块,那么执行时会按照这些静态代码块的定义顺序来执行
- 若是在静态代码块中存在调用,那么只能调用静态的属性和方法,不能调用非静态的属性和方法
非静态代码块特点(又叫构造代码块,有点类似构造函数)
- 非静态代码块不使用static关键字进行修饰
- 非静态代码块的内部可以有输出语句
- 非静态代码块随着对象的创建而执行
- 每创建一个对象便会调用一次非静态代码块(因为非静态代码块是用于初始化对象的,因此,每次使用new关键字创建一个对象都会新增一个对象并使用非静态代码块对其初始化)
- 非静态代码块可以在创建对象时,对对象的属性进行初始化
- 若是在一个类中定义了多个非静态代码块,则这些非静态代码块会按照定义的先后顺序来执行
- 非静态代码块中,可以调用该类的静态属性、静态方法、非静态属性、非静态方法(因为静态的内容是随着类的加载而加载的,而非静态内容是在静态内容之后被加载的,因此非静态代码块调用已经存在的静态内容是完全没有问题的)
在一个对象实例化时的执行顺序
1.首先执行静态代码块,在类初始化执行。静态代码块只执行一次
2.其实执行非静态代码块,在对象实例化new时执行,每次实例化都会执行一次
3.最后执行构造函数
代码:
对象类
public class CodePiece {public static final String s="dd";//分静态代码块{int i=0;System.out.println("非静态代码块.......2");}//静态代码块static {int i1=0;System.out.println("静态代码块........1");}private int i=2;public CodePiece(){System.out.println("构造函数.............3");// System.out.println("i="+i);}}
测试
Testpublic void t1() throws ClassNotFoundException {// System.out.println( CodePiece.s);//第一次要执行静态代码块Class cls=Class.forName("com.jsoft.ref.CodePiece");//第二次将不会执行静态代码块Class cls2=Class.forName("com.jsoft.ref.CodePiece");CodePiece v1=new CodePiece(); //执行非静态代码代码和构造函数CodePiece v2=new CodePiece();//执行非静态代码代码和构造函数}
效果
静态代码块........1
非静态代码块.......2
构造函数.............3
非静态代码块.......2
构造函数.............3
应用场景
1.我们只需要类加载一次执行的时候,我们使用静态代码块(应用场景多)
2.如果有多个构造函数,都要执行共有的代码,我们把这个部分代码放置到非静态代码块里
2.9.2内部类
定义
把一个类定义在令一个类里叫内部类,内部类分为静态内部类和非静态内部类两种,静态内部类用 static关键字修饰;内部类也可以定义成只有外部类能访问的私有类
public class MuCls {private Integer id;//非静态内部内类public class InnerClass1{}//静态内部类public static class InnerClass2{}//如果一个内部类不想让外部访问,可以声明一个私有的内部类privae class InnerClass3{}
}
内部类语法:内部类和外部类可以非常方便的通信
A{ class B{} }
| 类型 | 外部访问内部 | 内部访问外部 |
|---|---|---|
| 非静态内部类 | B b=new B(); b.字段 b.方法() | 1.外部类非静态字段或者方法: A.this.字段 A.this.方法() 2.外部类静态字段或方法 : A.字段 A.方法() |
| 静态内部类 | 1.静态字段和方法: B.字段 B.方法() 2.非静态字段和方法: B b=new B(); b.字段 b.方法() | 1.外部类非静态字段或者方法: A a=new A(); a.字段; a.方法() 2.外部类静态字段或方法 : A.字段 A.方法() |
注意事项:
1.非静态内部类里不能有静态的字段和方法
2.内外部类通信,和 private public无关,因为都在同一个类里
3.一般情况下代码外部类为主,所以非静态内部类使用多一些
public class MuCls {private Integer id;public static String type;public void outM1(){System.out.println("外部类方法");}//操作非静态内部类public void outM2(){//访问非静态内部类,必须用new实例化InnerClass1 innerClass1=new InnerClass1();//访问内部类字段Integer i=innerClass1.id; //不管内部类字段是private还是public都可以访问//调用内部类方法innerClass1.innerM1();}//访问静态内部类public void outM3(){//访问静态内部类的静态字段和属性,可以直接访问Integer sex=InnerClass2.sex;InnerClass2.help();//访问非静态字段和属性,还是要new 内部类InnerClass2 innerClass2=new InnerClass2();//访问内部类字段String name=innerClass2.name; //不管内部类字段是private还是public都可以访问//调用内部类方法innerClass2.innerM2();}//外部静态方法public static void outM4(){System.out.println("外部类静态方法");}//非静态内部内类//注意非静态类里不能用static修饰字段和方法public class InnerClass1{private Integer id;public void innerM1(){System.out.println("非静态类方法innerM1()");}//访问外部类public void innerM2(){// 外部类非静态字段或者方法:外部类名.this.字段或者方法Integer outId=MuCls.this.id; //非静态字段MuCls.this.outM1();//非静态方法//外部类静态字段或方法:外部名类.字段或者方法String outType=MuCls.type;//静态字段MuCls.outM4();//静态方法}}//静态内部类//静态类里可以用static修饰字段和方法public static class InnerClass2{//内部类静态字段private static Integer sex;private String name;//内部类静态方法public static void help(){}public void innerM2(){System.out.println("非静态类方法innerM2()");}//访问外部类public void innerM3(){// 静态类不能直接访问外部类的非静态字段和方法,需要new 外部类MuCls muCls=new MuCls();Integer outId=muCls.id;muCls.outM1();//外部类静态字段或方法:外部名类.字段或者方法String outType=MuCls.type;//静态字段MuCls.outM4();//静态方法}}
}
第三方类调用含有内部类的类
A{ B{} }
| 非静态内部内 | 静态内部类 |
|---|---|
| 1.得到内部对象: A.B b=new A().new B(); 2.调用内部类方法: b.方法() | 1.访问静态类里静态方法和字段: A.B.字段 A.B.方法() 2.访问内部类非静态字段和方法: A.B b=new A.B(); b.字段; b.方法(); |
public class InnerTest {/***非静态内部类测试1.外部调用必须先实例化外部类获得外部类的对象2.获得内部类对象=外部类的对象.new 内部类名*/@Testpublic void t3(){MuCls muCls=new MuCls();//得到内部类对象MuCls.InnerClass1 innerClass1=muCls.new InnerClass1();//调用内部类方法innerClass1.innerM1();}/***静态内部类调用测试1.内部静态类里面的静态属性和方法可以直接访问2.内部静态类的实例化和非静态类不一样,可以直接new*/@Testpublic void t4() {//1.访问静态内部类的静态字段和方法MuCls.InnerClass2.help();//2.访问静态内部类的非静态字段和方法//静态内部类,实际上是独立的一个类,可直接new生成对象,和非静态内部内不一样MuCls.InnerClass2 innerClass2=new MuCls.InnerClass2();innerClass2.innerM2();}
}
什么场景下使用内部类
有时候一个类太复杂,我们把一个类里面的一些属性和方法抽取成一个内部类,隐藏复杂逻辑
,而且内部方法需要互相方便的访问,比抽取成一个外部类更方便。
2.9.3匿名类
什么是匿名类?
- 使用 Java 编程时,常常需要创建不会被再次使用的对象。
在这种情况下,非常适合使用一种特殊的内部类:匿名内部类。
这种类没有名称,是在同一条语句中声明和创建的。
要使用匿名内部类,可将引用对象的代码替换为关键字 new、对构造函数的调用以及用大括号({和})括起的类定义。
既然是匿名类,所以你无法在别的地方实例化和使用这个类。 - 匿名内部类也可用于接口(interface)的实现
语法: new 类名().方法()
准备类:
public class NoName {public void play(){System.out.println("执行NoName.play()");}public void eat(){System.out.println("执行NoName.eat()");}}public interface NoNameInterface {public void play();public void eat();
}
声明一个NoName的匿名对象
@Testpublic void t1(){//正常声明对象NoName noName=new NoName();noName.play();//如果我们这个noName不在其他地方使用,而且只调用一个方法,就可以简写如下:new NoName().play();}
更常见的一种写法
new 类名或者接口名() {重写方法;
}
重写匿名类的方法
//在方法体里重写匿名类的方法@Testpublic void t2() {new NoName() { //重写NoName类的play()方法@Overridepublic void play() {System.out.println("重写方法play()");}}.play();}//重写参数类里的方法@Testpublic void t3() {param(new NoName() {@Overridepublic void play() {System.out.println("重写参数类的play()");}});/*** 等价于public class A extends NoName{public void play() {System.out.println("重写参数类的play()");}}NoName a=new A();param(a);*/}private void param(NoName noName) {noName.play();}
接口的匿名实现类,这种写法场景更多
代码
//接口实现匿名类的写法@Testpublic void t4(){new NoNameInterface(){@Overridepublic void play(){System.out.println("接口实现匿名类.play()");}@Overridepublic void eat(){System.out.println("接口实现匿名类.eat()");}}.play();}//如果接口里有多个方法被调用,则可以用下面这种方式@Testpublic void t5(){NoNameInterface service= new NoNameInterface(){@Overridepublic void play(){System.out.println("接口实现匿名类.play()");}@Overridepublic void eat(){System.out.println("接口实现匿名类.eat()");}};service.play();service.eat();}//方法参数是接口的匿名实现类写法@Testpublic void t6(){param2(new NoNameInterface(){@Overridepublic void play() {System.out.println("参数接口实现匿名类.play()");}@Overridepublic void eat() {System.out.println("参数接口实现匿名类.eat()");}});}private void param2(NoNameInterface service) {service.play();}
在使用匿名内部类的过程中,我们需要注意如下几点:
1、使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。
2、匿名内部类中是不能定义构造函数的。
3、匿名内部类中不能存在任何的静态成员变量和静态方法。
4、匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
2.10枚举
2.11 集合
2.12 日期类LocalDate
2.13 java泛型及通配符
2.14文件流IO
相关文章:
java进阶(二)-java小干货
java一些精干知识点分享 2. java小干货2.1循环遍历2.2可变参数2.3 list和数组转化2.3.1 数组转list2.3.2 list转数组 2.4 值传递和地址传递2.4.1值传递2.4.2 地址传递2.4.3易错点总结 2.5 数据类型2.5.1基础知识2.5.2 基础数据和包装类 2.6 字符串2.6.1 char/String区别2.6.2 .…...
layui(iconPickerFa)图标选择器插件,主要用于后台菜单图标管理
话不多说直接上代码 在页面中引入如下代码 <link rel"stylesheet" href"/template/admin/layui-v2.5.6/css/layui.css"> <script type"text/javascript" src"/template/admin/layui-v2.5.6/layui.js"></script> &…...
RabbitMQ入门指南(九):消费者可靠性
专栏导航 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、消费者确认机制 二、失败重试机制 三、失败处理策略 四、业务幂等性 1.通过唯一标识符保证操作的幂等性 2.通过业务判断保证操作的幂等性 总结 前言 RabbitMQ是一个高效、可靠的开源消息队列系…...
MySQL的聚合函数、MySQL的联合查询、MySQL的左连接右连接内连接
MySQL的聚合函数 MySQL聚合函数是在数据库中对数据进行聚合操作的函数。它们将多行数据作为输入,并返回单个值作为结果。 常用的MySQL聚合函数包括: COUNT:计算符合条件的行数。SUM:对指定列的数值进行求和操作。AVG࿱…...
RKNN Toolkit Lite2 一键安装和测试,sh脚本
RKNN Toolkit Lite2 安装和测试教程 本教程旨在指导用户如何使用提供的shell脚本来安装和测试RKNN Toolkit Lite2,适用于需要在Linux系统上部署和测试AI模型的开发者。 简介 RKNN Toolkit Lite2是一个高效的AI模型转换和推理工具包,专为Rockchip NPU设…...
探索中国制造API接口:解锁无限商机,引领制造业数字化转型
一、概述 中国制造API接口是一种应用程序接口,专门为中国制造行业提供数据和服务。通过使用API接口,开发者可以轻松地获取中国制造的商品信息、供应商数据、生产能力等,从而为他们的应用程序或网站提供更加丰富的内容和功能。 二、API接口的…...
CentOS上安装MySQL 8.0的详细教程
CentOS上安装MySQL 8.0的详细教程 大家好,我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我将为大家分享一篇关于在CentOS上安装MySQL 8.0的详细教程。MySQL是一个强大…...
[RISCV] 为android14添加一个新的riscv device
本篇博客将基于android-14-r18添加Sifive unmatched板子的支持。 Setup build envoronment Establishing a build environment $ sudo apt install git-core gnupg flex bison build-essential zip curl zlib1g-dev libc6-dev-i386 libncurses5 x11proto-core-dev libx11-de…...
【Fastadmin】通用排序weigh不执行model模型的事件
在model模型类支持的before_delete、after_delete、before_write、after_write、before_update、after_update、before_insert、after_insert事件行为中,我们可以快捷的做很多操作,如删除缓存、逻辑判断等 但是在fastadmin的通用排序weigh拖动中无法触发…...
logstash收集华为、H3C、Cisco交换机日志
网络设备配置 将 syslog-ip 替换成服务器的IP地址。 Huawei info-center loghost source interface info-center loghost syslog-ip local-time facility local6 H3C info-center loghost source interface info-center loghost syslog-ip facility local5 Aruba logging arm …...
云上荆楚丨云轴科技ZStack成功实践精选(湖北)
湖北自古以来有九省通衢的美称,地处长江中游,富有荆楚之美誉,灵秀之蕴意。2022年湖北数字经济强省三年行动计划正式印发,计划到“十四五”末,数字经济核心产业增加值力争达到7000亿元,占GDP的比重超过12%。…...
C语言字符串处理提取时间(ffmpeg返回的时间字符串)
【1】需求 需求:有一个 “00:01:33.90” 这样格式的时间字符串,需要将这个字符串的时间值提取打印出来(提取时、分、秒、毫秒)。 这个时间字符串从哪里来的? 是ffmpeg返回的时间,也就是视频的总时间。 下…...
NC(65)元数据增加字段
以报销单主表er_bxzb表为例,增加15个字段字段以及两个其他业务所需字段 1、先在er_bxzb增加字段 增加字段 alter table er_bxzb add no_invoice char(1) default(N);alter table er_bxzb add is_enabled_taxation_cloud char(1) default(N);alter table er_bxzb a…...
SParC数据集介绍
导语 SParC是Text-to-SQL领域的一个多轮查询数据集。本篇博客将对该数据集论文和数据格式进行简要介绍。 SParC数据集概述 SParC是一个跨领域的多轮Text-to-SQL数据集。它包含有4298个问题轮次,大约有12k的自然语言问句到SQL标注的Question-SQL对。这些问题来自于…...
OpenGL 绘制Mesh数据(Qt)
文章目录 一、简介二、实现代码三、实现效果一、简介 Mesh数据的结构主要就是点与三角面片,因此本质上仍然是对三角面片进行绘制。这里我们借助VCG这个库实现对Mesh数据的读取,这个库相对简单轻巧,很方便使用。 二、实现代码 由于修改的部分很多,我们逐一进行解释一下: --…...
9.传统的轨道画线算法()
轨道画线分为以下步骤: 1.读取摄像头图片 2.图片灰度处理,截取轨道区域的图片 3.中值滤波处理,并区域取均值后做期望差的绝对值。本人通过一些轨道图片实验,用这种方法二值化得到的效果比caany算子等方法的效果好 4.二值化后再…...
F (1164) : B DS二叉排序树_有效的二叉排序树
Description 给你一个二叉树,判断其是否是一个有效的二叉排序树。 有效的二叉排序树定义如下: 1. 结点的左子树只包含小于当前结点的数。 2. 结点的右子树只包含大于当前结点的数。 3. 所有左子树和右子树自身必须也是二叉排序树。 Input 第一行输…...
结合el-upload修改支持上传图片、视频并预览
结合element plus的el-upload标签,实现上传图片和视频,并支持在线预览和放大 1、html部分 <el-form-item label"活动照片、视频"><el-uploadv-model:file-list"state.photoList":action"state.uploadUrl"accept…...
1.SQL - 概述
1. SQL语句分类 • 数据定义语言:简称DDL(Data Definition Language),用来定义数据库对象:数据库,表,列等。关键字:create,alter,drop等 • 数据操作语言:简称DML(Data …...
GaussDB数据库表创建行访问控制策略
目录 一、前言 二、GaussDB中的行访问控制 1、CREATE ROW LEVEL SECURITY POLICY语法 2、ALTER ROW LEVEL SECURITY POLICY语法 3、ROW LEVEL SECURITY策略与适配SQL语法关系 三、GaussDB中的行访问控制策略示例 1、实现GaussDB行访问控制的一般步骤 2、行访问控制策略…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
