8种基本数据类型
1-整型(4种)
长整型数值-后缀L : 40000000000L
十六进制-前缀0x : 0xCAFE
八进制-前缀0 : 010 (易混淆,少用)
java7开始:
二进制-前缀0b : 0b1001 = 9(十进制)
下划线易读机制 :1_000_000 = 10000002-浮点类型(2种)
char类型 (1种)
JAVA应尽量避免使用char类型,1个java的char字符并不完全等于一个unicode的字符。char采用的UCS-2编码,是一种淘汰的UTF-16编码,编码方式最多有65536种,远远少于当今Unicode拥有11万字符的需求。java只好对后来新增的Unicode字符用2个char拼出1个Unicode字符。导致String中char的数量不等于unicode字符的数量。
char在Oracle(数据库)中,是固定宽度的字符串类型(即所谓的定长字符串类型),长度不够的就会自动使用空格补全。因此,在一些特殊的查询中,就会导致一些问题,而且这种问题还是很隐蔽的,很难被开发人员发现。一旦发现问题的所在,就意味着数据结构需要变更,可想而知,这是多么大的灾难啊。
所以,一个unicode字符(代码点)在java中有的是用一个代码单元表示,有的是用两个代码单元表示。String.length()
显示的是代码单元的数量。
要想知道字符串中代码点的数量,需要使用int UnicodeCount = StringA.codePointCount(0,StringA.length())
StringA.charAt(n)
返回位置n的代码单元,当此位置位“半个Unicode字符时”容易出现乱码,或者?string.offsetByCodePoints(0, i);
将返回第i个代码点的序号(从0编号),如果第i个代码点占有a,a+1两个代码单元将返回a+1.
随后我们可以通过StringcodePointat(序号)返回第i个代码点,单如果第i个代码点为双字符表示,此方法仍然不能显示该字符。
综上所述,我们应当尽量避免java中char类型的使用。
boolean类型(1种)
两种值- true 和 false
访问修饰符
面向对象三大特征
- 继承
通过继承,可以快速地创建新的类,可以提高代码的重用,程序的可维护性,节省大量创建新类的时间 ,提高我们的开发效率。 - 封装
封装是指把一个对象的状态信息(也就是属性)隐藏在对象内部,不允许外部对象直接访问对象的内部信息。但是可以提供一些可以被外界访问的方法来操作属性。 - 多态
一个父类,多个子类方法
Java8新特性
Java对象的特点?Java和C++语言的区别?
Java
- 平台无关性、 : 依靠Java虚拟机实现
- 面向对象 : 单继承
- 支持多线程
- 支持网络编程
- 编译解释并存
编译 .java -> .class
解释 .class -> 机器码
Java 对内存的访问和释放更安全,没有指针可以直接访问内存,并且内存回收由GC完成。
Java单继承类,可以实现多个接口,C++多继承类。
String StringBuffer StringBuilder
异常
反射
类加载过程中,会为加载的类在堆区创建一个引用对象class,反射就是利用这个对象进行操作,可以创建该类的对象实例,访问该类的所有方法以及属性。
代理模式
JDK 动态代理类使用步骤
- 定义一个接口及其实现类;
- 自定义 InvocationHandler 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;
- 通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象
CGLIB 动态代理机制
DK 动态代理有一个最致命的问题是其只能代理实现了接口的类。
为了解决这个问题,我们可以用 CGLIB 动态代理机制来避免。
CGLIB 通过继承方式实现代理,很多知名的开源框架都使用到了[CGLIB](https://github.com/cglib/cglib), 例如 Spring 中的 AOP 模块中:如果目标对象实现了接口,则默认采用 JDK 动态代理,否则采用 CGLIB 动态代理。
JDK 动态代理和 CGLIB 动态代理对比
JDK 动态代理只能只能代理实现了接口的类或者直接代理接口,而 CGLIB 可以代理未实现任何接口的类。CGLIB 动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用,因此不能代理声明为 final 类型的类和方法。<br /> 就二者的效率来说,大部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更加明显
常见问题
- 为什么重写
**equals**
时必须重写**hashCode**
方法?
如果两个对象相等,则 hashcode 一定也是相同的。两个对象相等,对两个对象分别调用 equals 方法都返回 true。但是,两个对象有相同的 hashcode 值,它们也不一定是相等的 。因此,equals 方法被覆盖过,则**hashCode**
方法也必须被覆盖。
因为hashCode()
所使用的杂凑算法也许刚好会让多个对象传回相同的杂凑值。越糟糕的杂凑算法越容易碰撞,但这也与数据值域分布的特性有关(所谓碰撞也就是指的是不同的对象得到相同的hashCode
。
我们刚刚也提到了HashSet
,如果HashSet
在对比的时候,同样的 hashcode 有多个对象,它会使用equals()
来判断是否真的相同。也就是说hashcode
只是用来缩小查找成本。 - 重载和重写的区别
重载就是同样的一个方法能够根据输入数据的不同,做出不同的处理
重写就是当子类继承自父类的相同方法,输入数据一样,但要做出有别于父类的响应时,你就要覆盖父类方法 - 构造器 Constructor 是否可被 override?
Constructor 不能被 override(重写),但是可以 overload(重载),所以你可以看到一个类中有多个构造函数的情况。 - 在 Java 中定义一个不做事且没有参数的构造方法的作用
Java 程序在执行子类的构造方法之前,如果没有用 super()来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用 super()来调用父类中特定的构造方法,则编译时将发生错误,因为 Java 程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。 - String StringBuffer 和 StringBuilder 的区别是什么?
String
类中使用 final 关键字修饰字符数组来保存字符串StringBuilder
与StringBuffer
都继承自AbstractStringBuilder
类,在AbstractStringBuilder
中也是使用字符数组保存字符串char[]value
但是没有用final
关键字修饰,所以这两种对象都是可变的。stringBuffer
对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder
并没有对方法进行加同步锁,所以是非线程安全的。 - Java内存泄漏和内存溢出
内存泄漏:严格来说,只有对象不会再被程序用到了,但是 GC 又不能回收他们的情况,才叫内存泄漏。
由于这些对象不能被垃圾回收掉,这样的对象多了,有可能就会 OOM。
原因总结:- 存活时间长的对象引用了存活时间短的对象,比如单例对象(单例的生命周期和应用程序是一样长)含有不再使用的对象的引用
- 各种连接资源对象:数据库连接(dataSourse . getConnection()),网络连接(socket)和io连接必须手动close,否则是不能被回收的,这些资源连接都要在finally{}中手动关闭;
- 静态集合类:静态集合类含有对象引用,无法回收
解决方案:通过工具查看泄漏对象到GC Roots
的引用链,通过对象信息定位泄露代码的位置进行修改。
内存溢出:内存溢出就是没有空闲内存的情况:说明Java虛拟机的堆内存不够。
原因总结:
(1) Java虛拟机的堆内存设置不够。调整虚拟机参数,改变堆空间大小 -Xms600m -Xmx600m
(2) 存在内存泄漏情况,代码中创建了大量大对象,并且长时间不能被垃圾收集器收集(存在被引用)
- Java性能优化
代码层面 :查看业务日志,检查日志内容里是否有大量的报错产生,代码逻辑是否合理
批处理时,减少和数据库的交互次数,一次查询数据库返回结果,然后再在本地进行处理
异步编排,多线程处理,将没有逻辑关系的任务进行异步编排,即使有逻辑先后顺序也可以通过CompletableFuture 进行编排
内存相关 :是否出现了内存泄漏,导致或者OOM,或者GC频繁
内存划分不合理,导致GC频繁,深入分析业务代码,合理的设计新生代,老年代,Eden,Survivor区的大小。
垃圾回收: 选择合适的 GC 回收器
CPU相关: CPU 密集型的应用 或者 错误的死循环(1.8之前的HashMap,多线程操作会导致死循环) 或者 GC频繁
IO问题 : 磁盘 I/O、 网络 I/O
jstack 、jvisual => 线程堆栈快照 具体分析