-
java bridge method
public class BridgeTest<T> { public void test(T t) { } public static class Test extends BridgeTest<String> { @Override public void test(String t) { System.out.println(t); } } public static void main(String[] args) { System.out.println("BridgeTest.class 方法"); Method[] methods = BridgeTest.class.getDeclaredMethods(); for (Method method : methods) { System.out.println(method.getName() + ":" + Arrays.toString(method.getParameterTypes()) + "是否Bridge方法" + method.isBridge()); } System.out.println("Test.class 方法"); methods = Test.class.getDeclaredMethods(); for (Method method : methods) { System.out.println(method.getName() + ":" + Arrays.toString(method.getParameterTypes()) + "是否Bridge方法" + method.isBridge()); } } }
运行结果:
BridgeTest.class 方法 main:[class [Ljava.lang.String;]是否Bridge方法false test:[class java.lang.Object]是否Bridge方法false Test.class 方法 test:[class java.lang.String]是否Bridge方法false test:[class java.lang.Object]是否Bridge方法true
总结:BridgeTest java编译之后的test方法的参数是Object,即
test(Object)
。Test.class重写BridgeTest的test方法,然后Test.class有两个方法,test(String)
和test(Object)
,此时test(Object)
变为了桥方法 -
反射,获取泛型类型 java.lang.reflect.Type
java.lang.reflect.Type 子类包括ParameterizedType,GenericArrayType,TypeVariable,WildcardType,Classpublic class TypeTest { public <T> void test(List<String> a0, String[] a1, List<? extends Object> a2, T[] a3, T a4) { } public static void main(String[] args) { Method method = Arrays.stream(TypeTest.class.getDeclaredMethods()).filter(v -> v.getName().equals("test")) .findFirst().get(); Parameter[] params = method.getParameters(); for (Parameter param : params) { Type type = param.getParameterizedType(); if (param.getName().equals("arg2")) { ParameterizedType ptype = (ParameterizedType) type; System.out .println(param.getName() + "," + ptype.getActualTypeArguments()[0].getClass().getSimpleName()); } else { System.out.println(param.getName() + "," + type.getClass().getSimpleName()); } } } }
运行结果:
arg0,ParameterizedTypeImpl arg1,Class arg2,WildcardTypeImpl arg3,GenericArrayTypeImpl arg4,TypeVariableImpl
总结:
ParameterizedType:List,只要是带<>都是
GenericArrayType :T[],必须是 泛型[]
TypeVariable :T,必须是 泛型
WildcardType : ? extends Object ,?extends 类型 或者 ? super 类型 -
List<? super A>,List<? extends A>
添加、获取元素问题- 添加:? super A 为元素定义,所以应满足(? super A) a=其子类型,虽然不知道?是什么类型,但是知道?的下界是A,那么a=必须是A或A的子类,如此不管?是什么,等式一定成立。同理(? extends A) a=子类型,但是?代表A的子类型,无限下界,那么a=任何其他类型都不能成立,因为不能保证一定是?的子类型,所以只能添加null元素。
- 获取:x=? super A ,? 是A的父类,无限上界,所以x只能是Object,? extends A,?的上界是A,所以x只能用A或A的父类。
-
三目运算符返回值规则
例1:x > 4 ? 1.9 : 1;
结果为double类型,类型不同会进行类型提升,浮点数高于非浮点数,占字节高的多余占字节低的
例2:x > 4 ? new Integer(2) : 1;
当表达式有基本类型和对象类型时,对象类型会被拆箱 -
四中引用
- Strong Reference :new 出的对象
- Soft Reference:当对象是Soft reference可达时,gc可能会向操作系统申请更多内存,而不是直接回收它,当实在没辙了才回收它。
- WeakReference:一旦gc发现对象是weak reference可达就会把它放到ReferenceQueue中,然后等下次gc时回收它;
- Phantom Reference:最弱,很少用到
强弱关系:Strong Reference>Soft Reference>WeakReference> Phantom Reference
-
抽象类也可以有构造方法,也可以new ,类似接口,如 new AbstractClass(){};
-
class.getClassLoader().getResource()
,参数只能是classpath中的资源,classpath外无法获取到。如class.getClassLoader().getResource(“..”)
将返回null。 -
关于Class对象何时被回收
接口不会被卸载,除非ClassLoader是不能到达的,被BootstrapClassLoader加载的类不会被卸载。也就是说BootstrapClassLoader加载的部分基本不可能被卸载。 -
equals和hashCode
将对象放入到集合中时,首先判断要放入对象的hashcode值与集合中的任意一个元素的hashcode值是否相等,如果不相等直接将该对象放入集合中。如果hashcode值相等,然后再通过equals方法判断要放入对象与集合中的任意一个对象是否相等,如果equals判断不相等,直接将该元素放入到集合中,否则不放入。 -
java中String.length只的是字符数量,并不是字节数量。
-
接口中的方法修饰符只允许public&abstract
-
方法重写
- 子类中的方法的访问级别不能低于父类中该方法的访问级别
- 子类中方法抛出的异常范围不能大于父类中方法抛出的异常的范围
13.** 方法重载**
只要能区分开为不同的方法即可
-
异常捕获
try { int k=2/0; } catch (ArithmeticException e) { // TODO: handle exception System. out.println(0); } catch (Exception e) { // TODO: handle exception System. out.println(1); }
只会捕获子异常,且catch的顺序必须是先子后父(虽然父不会触发)
-
>>
变小,<<
变大 (绝对值) -
代码是否错误
例1:main方法中对象访问类静态私有变量16.public class WeiTest { private static int x=100; public WeiTest() { // TODO Auto-generated constructor stub } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub WeiTest hs1= new WeiTest(); hs1. x++; } }
例2:方法中访问同类型对象私有变量
public class PrivateTest { private String k; public PrivateTest(){ } public void setk(PrivateTest pt){ k=pt. k; } public static void main(String[] args) { //new PrivateTest(new PrivateTest()); } }
例3:浮点数定义
float b=.1f; float c=0.f;
以上都可以编译通过
-
a==null 回收问题
List<Object> list=new ArrayList<Object>(); String a=new String("b"); list.add(a); a=null; System.out.println(list.get(0).toString());//输出b
a=null 但是list还包含String(“b”)对象,String(“b”)并没有被回收;
-
查找资源
class.getResource(path)最终也会通过class.getClassLoader().getResource(finalpath)来查找资源,在这之前先要把path转换成finalpath,规则如下:
path finallpath
/开头 src下
非/开头 class所在的包下 -
基本对象类型拆包可能引起空指针
Integer i =null ; SupplierShopReply ssr=tourismBusinessSettingService.findSupplierShopByAgencyId(i);
如果不仔细看的话,这个语句只有tourismBusinessSettingService可能出现空指针异常。但是findSupplierShopByAgencyId(int i)的定义中参数是个基本类型,所以i==null时,由于要进行拆包操作也可能出现空指针。
-
Calendar.set(2016,5,1) 结果:2016.6.1, 月是0开始,天是1开始
-
SortedSet去重时用 使用它的 compareTo(或 compare)方法对所有元素进行比较
-
java锁块中不可以在加数据库锁
-
基本类型和其包装类型“==“比较会自动拆包。
-
正则表达式替换
“ab\n”.replaceAll(“ab\n”, “#”);
“ab\n”.replaceAll(“ab\n”, “#”);
两个结果是一样的,区别第一个\n是正则表达式,第二个\n是换行符 -
new File(“a.test”);相对路径为当前项目目录
-
getGenericSuperclass()意义
获取泛型实际类型public static abstract class Fan<T> { } // 返回的是Fan<String>而不是Fan new Fan<String>(){}.getClass().getGenericSuperclass()
-
超过最大值
int h=Integer.MAX_VALUE; int n=h*2; System.out.println(n);
结果是个负数
-
java io 的默认路径为use.dir 即项目的根目录
-
java各种代码块执行顺序
- 父类静态代码块-子类静态代码块-父类非静态代码块-父类构造方法-子类非静态代码块-子类构造方法。
- class.forName(“类全路径”); 会执行类的静态内容。
- 非静态代码块在静态之后,构造方法之前。abstract类可以执行非静态代码块。
-
泛型.newInstance()
是不可行的;constructor 泛型的实例化必须有显示的构造函数 -
Condition.await操作会释放当前的线程持有的锁(当前线程必须持有锁,否则会抛异常)
-
两个整数&操作结果是<=最小值
-
Thread.interrupt()
为线程添加中断状态,所有能响应中断的方法,检测到该状态后会抛出中断异常,并清除中断状态 -
ConcurrentLinkedQueue.size() 要遍历一遍集合,很慢,所以尽量要避免用size而改用isEmpty()
-
ConcurrentLinkedQueue 出队cas理解
从头结点取出元素,再将头结点赋null之前,再次取出头结点的值,如果头结点仍未该元素,则置头结点的值为null,则此次取值成功,反之,如果头结点为null而不是原来取出的元素,则证明另一个线程已进行了cas操作,则此次取值失败,从头再来。 -
线程中的异常如果不被捕获或抛出到主线程中,是不能被发现的。callable通过future对象把异常跑出去,future.get()方法会抛出callabel的异常。即callable中的异常通过future.get()方法抛出,可以通过捕获future.get()来捕获callable中的异常。
-
死循环中如果没有io操作,要休眠,while(ture){sleep(1)…}
-
不同的对象hashCode()可以相等,相同的对象hashCode()必须相等
-
Lock.newCondition() 相当为锁上的线程分类,每一个条件就会创建一个分类,可以对每类线程单独控制
-
CopyOnWrite
CopyOnWrite在移除操作时会复制当前内存区域,会在新区域上进行操作,而读取操作仍在原区域操作,读和写操作的内存是独立的,这样就不会出现异常,这样可以提过读性能,但写性能会受到影响,也会占用更多内存。 -
对象创建的问题
- clone对象不会调用构造函数,对于构造很复杂的对象比new效率高。
- 序列化可以实现对象的深复制
-
弱引用的使用场景
-
用户创建对象时会创建强引用,以用户的角度出发在流程结束时创建的对象应该可被回收,但是所使用的的上层框架可能维持了对象的引用,这个时候上层框架可以考虑用弱引用的方式引用用户对象,这样用户流程结束强引用消失,只存在框架所保持的弱引用,这样对象可在gc时被回收。如TheadLocal,用户new ThreadLocal 时被线程Thread所引用,用户并不知道,用户的流程结束了,但是在线程池的情况下线程可能不会结束。
-
可以用在临时使用,不需要永久常驻内存的场景,如果对象没了可以在查
private SoftReference<Map<String, ChannelSkuMappingImportSimpleBO>> improtConfigCache; private ChannelSkuMappingImportSimpleBO getCacheImportConfig(String platformName) { Map<String, ChannelSkuMappingImportSimpleBO> map = null; if (improtConfigCache == null || (map = improtConfigCache.get()) == null) { map = channelSkuMappingImportConfigMapper.getAllValid().stream() .collect(Collectors.toMap(v -> v.getPlatformName(), Function.identity(), (oldV, newV) -> { logger.error(platformName + "存在重复的平台的信息"); return null; })); improtConfigCache = new SoftReference<Map<String, ChannelSkuMappingImportSimpleBO>>(map); } return map.get(platformName); }
-
-
cas和volatile联合使用组成乐观锁
//流程把operate改为1 volatile boolean lock; volatile int operate=0; while(operate==0){ if(lock){//有其他线程以获取到锁,则放弃cpu,并循环等待 Thread.yield(); }else if(U.compareAndSwapInt(this,lock, false, true)){//尝试获取锁 try { if (operate==0) {//锁内判断状态 operate=1; } } finally { lock= false;//释放锁 } } }
-
Pattern和Matcher联合使用可以达到边匹配边处理的效果,Matcher可以获取匹配的部分并进行处理
-
java 字符处理以utf-16方式存取和处理
-
sql in问题
//改为 id IN (862,872,883,886,893) 才是正确 SELECT * from test WHERE id IN ("862,872,883,886,893") SELECT * from test WHERE id IN (862) 这两个sql的结果是一样
-
sql join问题
A表 id code 1 a 1 b B表 pid code 1 a 2 b select * from B b left join A a on b.pid=a.id where b.code=a //结果是错的 关联后的样子 B A pid code id code 1 a 1 a 1 a 1 b 2 b 所以最终结果会是两条 正确的写法如下 select * from B b left join A a on b.pid=a.id where a.code=a
总结:在表关联做筛选的时候,如果筛选字段是多个表都有的,那么每个表都应该做筛选
-
json 转对象
复杂的json里有很多对象的值是一样的,其实他们是同一个对象,但在转换成java对象时很可能不是一个对象,这会造成内存的巨大浪费,所以在返回json数据时,像一对多这种情况,尽可能是一对多单向关联,减少对象数量 -
常量池
- java中基本类型的包装类的大部分都实现了常量池技术,这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。另外Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127时才可使用对象池,也即对象不负责创建和管理大于127的这些类的对象。
- String 常量池
String s3="hello"; String s4="hello"; System.out.println(s3==s4);//输出true
-
Java ServiceLoader使用
- 创建一个接口文件
- 在resources资源目录下创建META-INF/services文件夹
- 在services文件夹中创建文件,以接口全名命名
- 创建接口实现类
-
Collectors.toList() 返回的list类型是不确定的,有可能不是线程安全的
-
sql查询,字段如果需要需要计算,尽可能先计算,在传入sql,这有助于索引生效
-
数值计算问题
int createTime=1679303442; long milltime = createTime * 1000;//milltime=-28770736 ,错误的结果 milltime = (long) createTime * 1000; System.out.println(milltime);//milltime=1679303442000 ,正确的结果
错误的代码和下面的代码等价。错误的原因,是createTime*1000已经超过了整型最大值,会被截断,让后在转为long型。
int createTime=1679303442; int temp = createTime * 1000; long milltime=(int) temp;
-
浮点数之间的等值判断,基本数据类型不能用==来比较,包装数据类型不能用 equals来判断。BigDecimal 的等值比较应使用 compareTo()方法,而不是 equals()方法。 equals()方法会比较值和精度(1.0 与 1.00 返回结果为 false),而 compareTo()则会忽略精度。
-
使用 Instant 代替 Date,LocalDateTime 代替 Calendar,DateTimeFormatter 代替 SimpleDateFormat,官方给出的解释:simple beautiful strong immutable thread-safe。
-
对象占用内存大小估算
- 对象头,64位系统上占用16byte,如果对象是数组要再加4byte
- 对齐填充:确保对象的总长度为8字节的整数倍
- 引用类型:64位虚拟机上8byte
例子:对象头16+a 1 +c 4+d 1+e 8+f 4+f引用 8= 42+对象补齐6=48byte
class FieldTest{ byte a; int c; boolean d; long e; Integer f; }
经验:20万个对象(74个字段)400m内存
-
ConcurrentSkipListSet.add方法依据compareTo来判断是否重复对象,他查找和比较对象依据跳表的规律,即他不会查找和比较所有的对象,以便增加效率。必须定义严格的顺序规则,否则会加入重复元素。
-
CopyOnWriteArrayList 迭代器不支持更新操作。
-
动态代理
jdk通过实现接口的方式实现代理,cglib通过继承的方式实现代理,当被代理方法中调用被代理对象其他方法时,jdk代理和cglib代理方式效果不同,如下所述。-
jdk的方式
public class JdkProxy implements InvocationHandler { private Dest dest = new Dest();//需要目标对象 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("my jdk proxy:" + proxy.getClass().getSimpleName()); return method.invoke(dest, args);//实际调用的是目标对象的方法 } }
-
cgblib方式
public class CglibProxy implements MethodInterceptor{ public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("my cglib proxy:"+obj.getClass().getSimpleName()); return proxy.invokeSuper(obj, args);//实际上调用的仍是代理对象的方法 } }
-
-
gson会默认把对象中url地址进行url编码。
-
httpclient post 默认无法自动重定向
java 杂记
于 2023-04-12 11:37:59 首次发布