java 杂记

  1. 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) 变为了桥方法

  2. 反射,获取泛型类型 java.lang.reflect.Type
    java.lang.reflect.Type 子类包括ParameterizedType,GenericArrayType,TypeVariable,WildcardType,Class

       public 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 类型

  3. 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的父类。
  4. 三目运算符返回值规则
    例1:x > 4 ? 1.9 : 1;  结果为double类型,类型不同会进行类型提升,浮点数高于非浮点数,占字节高的多余占字节低的
    例2:x > 4 ? new Integer(2) : 1;  当表达式有基本类型和对象类型时,对象类型会被拆箱

  5. 四中引用

    • Strong Reference :new 出的对象
    • Soft Reference:当对象是Soft reference可达时,gc可能会向操作系统申请更多内存,而不是直接回收它,当实在没辙了才回收它。
    • WeakReference:一旦gc发现对象是weak reference可达就会把它放到ReferenceQueue中,然后等下次gc时回收它;
    • Phantom Reference:最弱,很少用到

    强弱关系:Strong Reference>Soft Reference>WeakReference> Phantom Reference

  6. 抽象类也可以有构造方法,也可以new ,类似接口,如 new AbstractClass(){};

  7. class.getClassLoader().getResource(),参数只能是classpath中的资源,classpath外无法获取到。如class.getClassLoader().getResource(“..”)将返回null。

  8. 关于Class对象何时被回收
    接口不会被卸载,除非ClassLoader是不能到达的,被BootstrapClassLoader加载的类不会被卸载。也就是说BootstrapClassLoader加载的部分基本不可能被卸载。

  9. equals和hashCode
    将对象放入到集合中时,首先判断要放入对象的hashcode值与集合中的任意一个元素的hashcode值是否相等,如果不相等直接将该对象放入集合中。如果hashcode值相等,然后再通过equals方法判断要放入对象与集合中的任意一个对象是否相等,如果equals判断不相等,直接将该元素放入到集合中,否则不放入。

  10. java中String.length只的是字符数量,并不是字节数量。

  11. 接口中的方法修饰符只允许public&abstract

  12. 方法重写

    • 子类中的方法的访问级别不能低于父类中该方法的访问级别
    • 子类中方法抛出的异常范围不能大于父类中方法抛出的异常的范围
      13.** 方法重载**
      只要能区分开为不同的方法即可
  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的顺序必须是先子后父(虽然父不会触发)

  14. >>变小,<<变大 (绝对值)

  15. 代码是否错误
    例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;
    

    以上都可以编译通过

  16. 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”)并没有被回收;

  17. 查找资源
    class.getResource(path)最终也会通过class.getClassLoader().getResource(finalpath)来查找资源,在这之前先要把path转换成finalpath,规则如下:
      path             finallpath
       /开头              src下
       非/开头            class所在的包下

  18. 基本对象类型拆包可能引起空指针

    Integer i =null ;
    SupplierShopReply  ssr=tourismBusinessSettingService.findSupplierShopByAgencyId(i);
    

    如果不仔细看的话,这个语句只有tourismBusinessSettingService可能出现空指针异常。但是findSupplierShopByAgencyId(int i)的定义中参数是个基本类型,所以i==null时,由于要进行拆包操作也可能出现空指针。

  19. Calendar.set(2016,5,1) 结果:2016.6.1, 月是0开始,天是1开始

  20. SortedSet去重时用 使用它的 compareTo(或 compare)方法对所有元素进行比较

  21. java锁块中不可以在加数据库锁

  22. 基本类型和其包装类型“==“比较会自动拆包。

  23. 正则表达式替换
    “ab\n”.replaceAll(“ab\n”, “#”);
    “ab\n”.replaceAll(“ab\n”, “#”);
    两个结果是一样的,区别第一个\n是正则表达式,第二个\n是换行符

  24. new File(“a.test”);相对路径为当前项目目录

  25. getGenericSuperclass()意义
    获取泛型实际类型

    public static abstract class Fan<T> {
    }
    // 返回的是Fan<String>而不是Fan
    new Fan<String>(){}.getClass().getGenericSuperclass()
    
  26. 超过最大值

    int h=Integer.MAX_VALUE;
    int n=h*2;
    System.out.println(n);
    

    结果是个负数

  27. java io 的默认路径为use.dir 即项目的根目录

  28. java各种代码块执行顺序

    • 父类静态代码块-子类静态代码块-父类非静态代码块-父类构造方法-子类非静态代码块-子类构造方法。
    • class.forName(“类全路径”); 会执行类的静态内容。
    • 非静态代码块在静态之后,构造方法之前。abstract类可以执行非静态代码块。
  29. 泛型.newInstance() 是不可行的;constructor 泛型的实例化必须有显示的构造函数

  30. Condition.await操作会释放当前的线程持有的锁(当前线程必须持有锁,否则会抛异常)

  31. 两个整数&操作结果是<=最小值

  32. Thread.interrupt()
    为线程添加中断状态,所有能响应中断的方法,检测到该状态后会抛出中断异常,并清除中断状态

  33. ConcurrentLinkedQueue.size() 要遍历一遍集合,很慢,所以尽量要避免用size而改用isEmpty()

  34. ConcurrentLinkedQueue 出队cas理解
    从头结点取出元素,再将头结点赋null之前,再次取出头结点的值,如果头结点仍未该元素,则置头结点的值为null,则此次取值成功,反之,如果头结点为null而不是原来取出的元素,则证明另一个线程已进行了cas操作,则此次取值失败,从头再来。

  35. 线程中的异常如果不被捕获或抛出到主线程中,是不能被发现的。callable通过future对象把异常跑出去,future.get()方法会抛出callabel的异常。即callable中的异常通过future.get()方法抛出,可以通过捕获future.get()来捕获callable中的异常。

  36. 死循环中如果没有io操作,要休眠,while(ture){sleep(1)…}

  37. 不同的对象hashCode()可以相等,相同的对象hashCode()必须相等

  38. Lock.newCondition() 相当为锁上的线程分类,每一个条件就会创建一个分类,可以对每类线程单独控制

  39. CopyOnWrite
    CopyOnWrite在移除操作时会复制当前内存区域,会在新区域上进行操作,而读取操作仍在原区域操作,读和写操作的内存是独立的,这样就不会出现异常,这样可以提过读性能,但写性能会受到影响,也会占用更多内存。

  40. 对象创建的问题

    • clone对象不会调用构造函数,对于构造很复杂的对象比new效率高。
    • 序列化可以实现对象的深复制
  41. 弱引用的使用场景

    • 用户创建对象时会创建强引用,以用户的角度出发在流程结束时创建的对象应该可被回收,但是所使用的的上层框架可能维持了对象的引用,这个时候上层框架可以考虑用弱引用的方式引用用户对象,这样用户流程结束强引用消失,只存在框架所保持的弱引用,这样对象可在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);
          }
      
      
      
  42. 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;//释放锁
              }
       }
    
    }
    
  43. Pattern和Matcher联合使用可以达到边匹配边处理的效果,Matcher可以获取匹配的部分并进行处理

  44. java 字符处理以utf-16方式存取和处理

  45. 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的结果是一样
    
  46. 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
    

    总结:在表关联做筛选的时候,如果筛选字段是多个表都有的,那么每个表都应该做筛选

  47. json 转对象
    复杂的json里有很多对象的值是一样的,其实他们是同一个对象,但在转换成java对象时很可能不是一个对象,这会造成内存的巨大浪费,所以在返回json数据时,像一对多这种情况,尽可能是一对多单向关联,减少对象数量

  48. 常量池

    • 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  
      
  49. Java ServiceLoader使用

    1. 创建一个接口文件
    2. 在resources资源目录下创建META-INF/services文件夹
    3. 在services文件夹中创建文件,以接口全名命名
    4. 创建接口实现类
  50. Collectors.toList() 返回的list类型是不确定的,有可能不是线程安全的

  51. sql查询,字段如果需要需要计算,尽可能先计算,在传入sql,这有助于索引生效

  52. 数值计算问题

    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;
    
  53. 浮点数之间的等值判断,基本数据类型不能用==来比较,包装数据类型不能用 equals来判断。BigDecimal 的等值比较应使用 compareTo()方法,而不是 equals()方法。 equals()方法会比较值和精度(1.0 与 1.00 返回结果为 false),而 compareTo()则会忽略精度。

  54. 使用 Instant 代替 Date,LocalDateTime 代替 Calendar,DateTimeFormatter 代替 SimpleDateFormat,官方给出的解释:simple beautiful strong immutable thread-safe。

  55. 对象占用内存大小估算

    • 对象头,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内存

  56. ConcurrentSkipListSet.add方法依据compareTo来判断是否重复对象,他查找和比较对象依据跳表的规律,即他不会查找和比较所有的对象,以便增加效率。必须定义严格的顺序规则,否则会加入重复元素。

  57. CopyOnWriteArrayList 迭代器不支持更新操作。

  58. 动态代理
    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);//实际上调用的仍是代理对象的方法
                 }
          }
      
  59. gson会默认把对象中url地址进行url编码。

  60. httpclient post 默认无法自动重定向

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值