JAVA 核心基础功能介绍
JAVA是一个面向对象的编程语言,面向对象就是一种抽象开发的思想包含封装、继承、多态,去掉这些概念也就是面向过程。应该是最初很多程序员使用面向过程编程,总结各种经验,对编程过程进行各种改进抽象出的更接近现实世界的最佳实鉴。通过面向对象有助与复杂系统的开发,有效提高编程效率。
- 抽象 将一类实体的共同特性抽象出来,封装在一个抽象类中
- 封装 将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法。
- 继承 在一个现有类型的基础上,通过增加新的方法或者重定义已有方法的方式(重载/重写),产生一个新的类型。
- 多态 通过传递给父类对象引用不同的子类对象从而表现出不同的行为,多态可为程序提供更好的可扩展性,同样也可以代码重用。
类直接的关系:
- 继承
- 实现
- 依赖 一个类A使用到了类B,属于非常弱的关系。
a.append(B b)
。UML中虚线箭头 - 关联 强依赖,长期的关系。B是A的成员变量
public class A { private B b = new B();}
。UML中实线箭头 - 聚合 整体与部分的关系,has-a,是可以分离的,各自有各自的生命周期。比如公司与员工。UML中空心菱形加实线箭头
- 组合 是contains-a的关系,比关系比聚合强就是强聚合。整体和部分不可分割。比如人和手。UML中实心菱形加实线箭头
基础写法
循环
for循环目前有4种写法
1 | for (int i=0; i<100; i++) {} |
1 | for (int i=0; i<100; i++) { |
常用函数
空值判断,最常见的问题之一
1 | String[] photo = new String[0]; // 初始化 |
类型转换
String.valueOf()
Integer.parseInt(String s)
- 错误用法:强制转换
(String)data //Cannot cast from Integer to String
split
注意: . 、 | 和 * 等转义字符,必须得加 \\
。
注意:多个分隔符,可以用 | 作为连字符。
public String[] split(String regex, int limit)
regex – 正则表达式分隔符。
limit – 分割的份数
split(" ", -1)
:
- 如果字符串最后一位有值则没有区别
- 如果最后N位都是分隔符,
split(" ")
不会继续切分,split(" ", -1)
会继续切分。 split(" ")
不会保留空值,但是split(" ")
会保留空值- 具体说明可以参看java API文档说明,通过开发工具可以直接查看注释
1 | public class StringTest { |
反射
Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包含了以下三个类:
- Field :可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段;
- Method :可以使用 invoke() 方法调用与 Method 对象关联的方法;
- Constructor :可以用 Constructor 创建新的对象。
Method invoke()调用的例子:
1 | // 1.获取字节码对象 |
List
LinkedList
- jdk1.6 双向循环列表
- jdk1.7 去掉了Head节点 变变成双向链表 但是有first last指针方便对头尾插入删除操作,节省了header节点空间
- 适合频繁插入删除
ArrayList
- 基于动态数组数组
- 可以通过下标定位
- 随机访问 get set优于LinkedList,LinkedList需要移动指针
- 插入效率没有LinkedList高
demo
1 | List<TreeNode> tmpList = new ArrayList<>(treeNodeMap.values()); // Map转List values() |
Set
具有去重功能,无序。
需要重写equals()与hashCode()方法,Set集合判断对象是否先等用到这两个方法(相当于通过hashcode生成箱子的编号),可以让工具自动生成
Object的代码:
1 | public String toString () { |
hashCode() 方法用于返回字符串的哈希码。
字符串对象的哈希码根据以下公式计算:s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
从实现来说,一般的HashCode方法会这样:return Attribute1.HashCode() + Attribute2.HashCode()…[+super.HashCode()]
1 |
|
关键字
- transient关键字 实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化.transient关键字只能修饰变量,而不能修饰方法和类
- legth size() length是数组的一个属性,在获取值的时候是按属性的方法获取。而size()是链表的一个方法,用于获取链表的长度
<<左移动 >>右移动相当于除以2 ~ 取反
- static 静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化,按照定义的顺序,顺序初始化,调用内部类的静态成员变量,会先执行静态代码块。静态代码块:全局,不管new多少次,只会初始化1次
选择单例还是static
只有加载资源/需要初始化并比较慢的类,才去使用单例。单例:多方法,有状态。静态方法:工具,无状态(也能支持有状态),纯函数。其实全局静态变量(类)就是单例模式在语言层面上的一种实现。static变量使用的时候是可以多个类定义相同的对象的。static是在容器加载的时候就已经加载到内存中,所以static方法和变量不宜过度使用,有选择的使用,如果一个方法和他所在类的实例对象无关,那么它就应该是静态的,否则就应该是非静态。因此像工具类,一般都是静态的。如果我们确实应该使用非静态的方法,但是在创建类时又确实只需要维护一份实例时,就需要用单例模式了。从功能上讲:单例模式可以控制单例数量;可以进行有意义的派生;对实例的创建有更自由的控制;比如加载的配置信息,从面向对象的角度考虑应该使用单例模式。
连接池可以使用单例,是说连接池只有一个,池里面的链接可以有多个比如30个。还有Service层与dao层,service层要频繁调用dao层,但是不需要每次都new,dao层没有跟对象相关的值变量,可以用单例实现dao,spring就是这么管理的,dao可以去连接池里取一个链接进行访问数据库,单例支持多线程访问要实现同步得加synchronized
具体使用可以参考:Springboot、Mybatis、Netty等开业框架源码
Netty:ByteToMessageDecoder.MERGE_CUMULATOR
Mybatisplus:
1 | SqlCondition |
注意:new一个对象里面的成员变量也会被new一份出来,虽然里面成员变量使用了单例创建但是外层对象new一下还是会导致创建多个不同成员对象。线程比较多的程序可用通过dump查看内存状态
static test
修改static值后其他对象获取该值也一样跟着修改:
1 | public class StaticTest { |
递归
递归边界,递归公式
递归次数过多容易造成栈溢出
尾递归可以复用栈帧
回调的写法
1 | public interface Callback { |
正则表达式
匹配出.数字.部分内容
1 | String str = "a.b.32.cd.323.f"; |
java WEB 部署
注意: 部署多个tomcat 8080访问端口跟关闭端口都要改。
概念理解
值传递与引用传递
新建Test.java
1 | /** |
重写
子类重写父类方法的时候还可以继续调用父类的方法
1 |
|
开发中可能会遇到的处理
用整数表示下拉框多个值
比如 3
的二进制11
代表 1,2
。每个二进制位可以代表一个下拉框输入项
1 | // 处理方式循环二进制字符串位数,把各个位数非0的数值计算出来. 1*2 + 1*1 → '2,1' |
运行
jar包运行方式
java -jar xxx.jar
。 需要jar包中manifest.mf
文件包含入口类内容Main-Class: xxx.xx.XxxMainClass
.sh
.bat
执行脚本。可以通过脚本配置各种启动参数环境变量,方便引用第三方包。例子:创建test.sh,lib目录,下面放入a.jar,b.jar,c.jar,启动AppMain.class可以放在其中jar中运行结果1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17!/bin/bash
dir=`dirname $0`
workpath=`cd $dir;pwd`
JAVA_OPTS="-server"
JAVA_OPTS="$JAVA_OPTS -Xmx1024m"
JAVA_OPTS="$JAVA_OPTS -Duser.dir=$workpath"
for oneJar in ./lib/*.jar
do cp=$cp:$oneJar
done
java $JAVA_OPTS -classpath $cp vip.infotech.AppMain
echo " =============================================================================="
echo $dir
echo $0
echo $JAVA_OPTS
echo $cp
echo $oneJar
echo "java" $JAVA_OPTS "-classpath" $cp "vip.infotech.AppMain"1
2
3
4
5
6
7==============================================================================
.
./test.sh
-server -Xmx1024m -Duser.dir=/root
:./lib/a.jar:./lib/b.jar:./lib/c.jar
./lib/c.jar
java -server -Xmx1024m -Duser.dir=/root -classpath :./lib/a.jar:./lib/b.jar:./lib/c.jar vip.infotech.AppMain
war
web项目tomcat下用的是war包。可以用7zip
压缩包工具更新war包中的文件。
新特性
声明式编程
类似sql语句。
1 | int count = students.stream() |
其他功能
Runtime.getRuntime().addShutdownHook(shutdownHook);
当jvm关闭的时候,会执行系统中已经设置的所有通过方法addShutdownHook添加的钩子,当系统执行完这些钩子后,jvm才会关闭。所以这些钩子可以在jvm关闭的时候进行内存清理、对象销毁等操作- 实体类类型统一,比如对于数据库bigint使用Long类型存储,其他整型都统一使用Integer
异常可能原因
栈溢出
调用层级过深或者递归调用没有正常退出,函数无限循环调用自己等
gc overhead limit exceeded
由于数据库问题,业务积压也可能导致内存不够用。也就是本来业务处理完内存是要释放的,由于某些原因导致业务无法完全执行完毕,新业务有过来处理。
while循环创建对象?
读取大文件-XX:-UseGCOverheadLimit
延后出错时间
java.net.SocketTimeoutException: Read timed out
增加超时时长
删掉超时时长配置
tomcat配置,增加disableUploadTimeout="true"
或者keepAliveTimeout="100000"
1 | <!--disableUploadTimeout默认值是false--> |
集合工具类
1 | /** |