Java
Java 是一种面向对象的语言,有两个明显特性:
跨平台能力:一次编写,到处运行(Write once,run anywhere);
垃圾收集:
Java 通过字节码和 Java 虚拟机(JVM)这种跨平台的抽象,屏蔽了操作系统和硬件的细节,这也是实现「一次编译,到处执行」的基础。
Java 通过垃圾收集器(Garbage Collector)回收分配内存,大部分情况下,程序员不需要自己操心内存的分配和回收。
JVM、JRE、JDK 关系
JVM:Java Virtual Machine 是 Java 虚拟机,Java 程序需要运行在虚拟机上,不同的平台有自己的虚拟机,因此 Java 语言可以实现跨平台。
JRE:Java Runtime Environment,包括 Java 虚拟机和 Java 程序所需的核心类库等。
核心类库主要是 java.lang 包:包含了运行 Java 程序必不可少的系统类,如基本数据类型、基本数学函数、字符串处理、线程、异常处理类等,系统缺省加载这个包如果想要运行一个开发好的 Java 程序,计算机中只需要安装 JRE 即可。
JDK:Java Development Kit是提供给 Java 开发人员使用的,其中包含了 Java 的开发工具,也包括了 JRE。
所以安装了 JDK,就无需再单独安装 JRE 了。其中的开发工具:编译工具(javac.exe),打包工具(jar.exe) 等。
面向对象四大特性
1、抽象
抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。
另外,抽象是一个宽泛的设计思想,开发者能不能设计好代码,抽象能力也至关重要。
很多设计原则都体现了抽象这种设计思想,比如基于接口而非实现编程、开闭原则(对扩展开放、对修改关闭)、代码解耦(降低代码的耦合性)等。
在面对复杂系统的时候,人脑能承受的信息复杂程度是有限的,所以我们必须忽略掉一些非关键性的实现细节。
2、封装
把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问。
通过封装,只需要暴露必要的方法给调用者,调用者不必了解背后的业务细节,用错的概率就减少。
3、继承
使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。
通过使用继承我们能够非常方便地复用以前的代码,需要注意的是,过度使用继承,层级深就会导致代码可读性和可维护性变差。
关于继承如下 3 点请记住:
子类拥有父类非 private 的属性和方法。
子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
子类可以用自己的方式实现父类的方法。
4、多态
所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定。即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。
在 Java 中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。
多态也是很多设计模式、设计原则、编程技巧的代码实现基础,比如策略模式、基于接口而非实现编程、依赖倒置原则、里式替换原则、利用多态去掉冗长的 if-else 语句等等。
Java 语言是如何实现多态的
Java 实现多态有三个必要条件:继承、重写、向上转型。
继承:在多态中必须存在有继承关系的子类和父类。
重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。
重载与重写
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
重载:发生在同一个类中,方法名相同参数列表不同(参数类型不同、个数不同、顺序不同),与方法返回值和访问修饰符无关,即重载的方法不能根据返回类型进行区分。
重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类(里氏代换原则);如果父类方法访问修饰符为 private 则子类中就不是重写。
java对象-PO、BO、VO、DTO、DAO、POJO
PO(Persistant Object) 持久对象
用于表示数据库中的一条记录映射成的 java 对象。PO 仅仅用于表示数据,没有任何数据操作。通常遵守 Java Bean 的规范,拥有 getter/setter 方法。
可以理解一个PO就是数据库中的一条记录;可以理解某个事务依赖的原始数据;好处是可以将一条记录最为一个对象处理,可以方便转化为其他对象
BO(Business Object) 业务对象
封装对象、复杂对象,里面可能包含多个类主要作用是把业务逻辑封装为一个对象。这个对象可以包括一个或多个其它的对象。
比如一个简历,有教育经历、工作经历、社会关系等等。我们可以把教育经历对应一个PO,工作经历对应一个PO,社会关系对应一个PO。建立一个对应简历的BO对象处理简历,每个BO包含这些PO。这样处理业务逻辑时,我们就可以针对BO去处理。
VO(Value Object) 表现对象
前端界面展示;value object值对象;ViewObject表现层对象;主要对应界面显示的数据对象。对于一个WEB页面,或者SWT、SWING的一个界面,用一个VO对象对应整个界面的值;对于Android而言即是activity或view中的数据元素。
用于表示一个与前端进行交互的 java 对象。有的朋友也许有疑问,这里可不可以使用 PO 传递数据?实际上,这里的 VO 只包含前端需要展示的数据即可,对于前端不需要的数据,比如数据创建和修改的时间等字段,出于减少传输数据量大小和保护数据库结构不外泄的目的,不应该在 VO 中体现出来。通常遵守 Java Bean 的规范,拥有 getter/setter 方法。
DTO(Data Transfer Object) 数据传输对象
前端调用时传输;也可理解成“上层”调用时传输;比如我们一张表有100个字段,那么对应的PO就有100个属性。但是我们界面上只要显示10个字段,客户端用WEB service来获取数据,没有必要把整个PO对象传递到客户端,这时我们就可以用只有这10个属性的DTO来传递结果到客户端,这样也不会暴露服务端表结构.到达客户端以后,如果用这个对象来对应界面显示,那此时它的身份就转为VO.
用于表示一个数据传输对象。DTO 通常用于不同服务或服务不同分层之间的数据传输。DTO 与 VO 概念相似,并且通常情况下字段也基本一致。但 DTO 与 VO 又有一些不同,这个不同主要是设计理念上的,比如 API 服务需要使用的 DTO 就可能与 VO 存在差异。通常遵守 Java Bean 的规范,拥有 getter/setter 方法
DAO(Data access object) 数据访问对象
这个大家最熟悉,和上面几个O区别最大,基本没有互相转化的可能性和必要.,主要用来封装对数据库的访问。通过它可以把POJO持久化为PO,用PO组装出来VO、DTO;
用于表示一个数据访问对象。使用 DAO 访问数据库,包括插入、更新、删除、查询等操作,与 PO 一起使用。DAO 一般在持久层,完全封装数据库操作,对外暴露的方法使得上层应用不需要关注数据库相关的任何信息。
POJO(Plain ordinary java object) 简单java对象
一个POJO持久化以后就是PO;直接用它传递、传递过程中就是DTO;直接用来对应表示层就是VO。
wait() 和 sleep
来源不同:
sleep()来自 Thread 类;
wait()来自 Object 类。
对于同步锁的影响不同:
sleep()不会该表同步锁的行为,如果当前线程持有同步锁,那么 sleep 是不会让线程释放同步锁的。
wait()会释放同步锁,让其他线程进入 synchronized 代码块执行。
使用范围不同:
sleep()可以在任何地方使用。
wait()只能在同步控制方法或者同步控制块里面使用,否则会抛 IllegalMonitorStateException。
恢复方式不同:两者会暂停当前线程,但是在恢复上不太一样。
sleep()在时间到了之后会重新恢复;
wait()则需要其他线程调用同一对象的 notify()/nofityAll()才能重新恢复。
String.format
用于创建格式化的字符串以及连接多个字符串对象。
format(String format, Object... args) 新字符串使用本地语言环境,制定字符串格式和参数生成格式化的新字符串。
format(Locale locale, String format, Object... args) 使用指定的语言环境,制定字符串格式和参数生成格式化的字符串。
1、显示不同转换符实现不同数据类型到字符串的转换
转 换 符 | 说 明 | 示 例 |
%s | 字符串类型 | "mingrisoft" |
%c | 字符类型 | 'm' |
%b | 布尔类型 | true |
%d | 整数类型(十进制) | 99 |
%x | 整数类型(十六进制) | FF |
%o | 整数类型(八进制) | 77 |
%f | 浮点类型 | 99.99 |
%a | 十六进制浮点类型 | FF.35AE |
%e | 指数类型 | 9.38e+5 |
%g | 通用浮点类型(f和e类型中较短的) |
|
%h | 散列码 |
|
%% | 百分比类型 | % |
%n | 换行符 |
|
%tx | 日期与时间类型(x代表不同的日期与时间转换符 |
public static void main(String[] args) {
String str=null;
str=String.format("Hi,%s", "王力"); //Hi,王力
str=String.format("Hi,%s:%s.%s", "王南","王力","王张"); //Hi,王南:王力.王张
System.out.printf("字母a的大写是:%c %n", 'A'); //字母a的大写是:A
System.out.printf("3>7的结果是:%b %n", 3>7); //3>7的结果是:false
System.out.printf("100的一半是:%d %n", 100/2); //100的一半是:50
System.out.printf("100的16进制数是:%x %n", 100); //100的16进制数是:64
System.out.printf("100的8进制数是:%o %n", 100); //100的8进制数是:144
System.out.printf("50元的书打8.5折扣是:%f 元%n", 50*0.85); //50元的书打8.5折扣是:42.500000 元
System.out.printf("上面价格的16进制数是:%a %n", 50*0.85); //上面价格的16进制数是:0x1.54p5
System.out.printf("上面价格的指数表示:%e %n", 50*0.85); //上面价格的指数表示:4.250000e+01
System.out.printf("上面价格的指数和浮点数结果的长度较短的是:%g %n", 50*0.85); //42.5000
System.out.printf("上面的折扣是%d%% %n", 85); //上面的折扣是85%
System.out.printf("字母A的散列码是:%h %n", 'A'); //字母A的散列码是:41
}
2、搭配转换符的标志
标 志 | 说 明 | 示 例 | 结 果 |
+ | 为正数或者负数添加符号 | ("%+d",15) | +15 |
− | 左对齐 | ("%-5d",15) | |15 | |
0 | 数字前面补0 | ("%04d", 99) | 0099 |
空格 | 在整数之前添加指定数量的空格 | ("% 4d", 99) | | 99| |
, | 以“,”对数字分组 | ("%,f", 9999.99) | 9,999.990000 |
( | 使用括号包含负数 | ("%(f", -99.99) | (99.990000) |
# | 如果是浮点数则包含小数点,如果是16进制或8进制则添加0x或0 | ("%#x", 99) ("%#o", 99) | 0x63 0143 |
< | 格式化前一个转换符所描述的参数 | ("%f和%<3.2f", 99.45) | 99.450000和99.45 |
$ | 被格式化的参数索引 | ("%1$d,%2$s", 99,"abc") | 99,abc |
public static void main(String[] args) {
String str=null;
//$使用
str=String.format("格式参数$的使用:%1$d,%2$s", 99,"abc"); //格式参数$的使用:99,abc
//+使用
System.out.printf("显示正负数的符号:%+d与%d%n", 99,-99); //显示正负数的符号:+99与-99
//补O使用
System.out.printf("最牛的编号是:%03d%n", 7); //最牛的编号是:007
//空格使用
System.out.printf("Tab键的效果是:% 8d%n", 7); //Tab键的效果是: 7
//.使用
System.out.printf("整数分组的效果是:%,d%n", 9989997); //整数分组的效果是:9,989,997
//空格和小数点后面个数
System.out.printf("一本书的价格是:% 50.5f元%n", 49.8);
//一本书的价格是: 49.80000元
}
3、日期和时间字符串格式化
转 换 符 | 说 明 | 示 例 |
c | 包括全部日期和时间信息 | 星期六 十月 27 14:21:20 CST 2007 |
F | “年-月-日”格式 | 2007-10-27 |
D | “月/日/年”格式 | 10/27/07 |
r | “HH:MM:SS PM”格式(12时制) | 02:25:51 下午 |
T | “HH:MM:SS”格式(24时制) | 14:28:16 |
R | “HH:MM”格式(24时制) | 14:28 |
public static void main(String[] args) {
Date date=new Date();
//c的使用
System.out.printf("全部日期和时间信息:%tc%n",date); // 九月 10 10:43:36 CST 2012
//f的使用
System.out.printf("年-月-日格式:%tF%n",date); // 年-月-日格式:2012-09-10
//d的使用
System.out.printf("月/日/年格式:%tD%n",date); // 月/日/年格式:09/10/12
//r的使用
System.out.printf("HH:MM:SS PM格式(12时制):%tr%n",date); //10:43:36 上午
//t的使用
System.out.printf("HH:MM:SS格式(24时制):%tT%n",date); //HH:MM:SS格式(24时制):10:43:36
//R的使用
System.out.printf("HH:MM格式(24时制):%tR",date); //HH:MM格式(24时制):10:43
}
转 换 符 | 说 明 | 示 例 |
H | 2位数字24时制的小时(不足2位前面补0) | 15 |
I | 2位数字12时制的小时(不足2位前面补0) | 03 |
k | 2位数字24时制的小时(前面不补0) | 15 |
l | 2位数字12时制的小时(前面不补0) | 3 |
M | 2位数字的分钟(不足2位前面补0) | 03 |
S | 2位数字的秒(不足2位前面补0) | 09 |
L | 3位数字的毫秒(不足3位前面补0) | 015 |
N | 9位数字的毫秒数(不足9位前面补0) | 562000000 |
p | 小写字母的上午或下午标记 | 中:下午 英:pm |
z | 相对于GMT的RFC822时区的偏移量 | +0800 |
Z | 时区缩写字符串 | CST |
s | 1970-1-1 00:00:00 到现在所经过的秒数 | 1193468128 |
Q | 1970-1-1 00:00:00 到现在所经过的毫秒数 | 1193468128984 |
public static void main(String[] args) {
Date date = new Date();
//H的使用
System.out.printf("2位数字24时制的小时(不足2位前面补0):%tH%n", date); //11
//I的使用
System.out.printf("2位数字12时制的小时(不足2位前面补0):%tI%n", date); //11
//k的使用
System.out.printf("2位数字24时制的小时(前面不补0):%tk%n", date); //11
//l的使用
System.out.printf("2位数字12时制的小时(前面不补0):%tl%n", date); //11
//M的使用
System.out.printf("2位数字的分钟(不足2位前面补0):%tM%n", date); //03
//S的使用
System.out.printf("2位数字的秒(不足2位前面补0):%tS%n", date); //52
//L的使用
System.out.printf("3位数字的毫秒(不足3位前面补0):%tL%n", date); //773
//N的使用
System.out.printf("9位数字的毫秒数(不足9位前面补0):%tN%n", date); //773000000
//p的使用
String str = String.format(Locale.US, "小写字母的上午或下午标记(英):%tp", date); //am
System.out.println(str);
System.out.printf("小写字母的上午或下午标记(中):%tp%n", date); //上午
//z的使用
System.out.printf("相对于GMT的RFC822时区的偏移量:%tz%n", date); //+0800
//Z的使用
System.out.printf("时区缩写字符串:%tZ%n", date); //CST
//s的使用
System.out.printf("1970-1-1 00:00:00 到现在所经过的秒数:%ts%n", date); // 1347246232
//Q的使用
System.out.printf("1970-1-1 00:00:00 到现在所经过的毫秒数:%tQ%n", date); // 1347246232773
}
fastjson
JSON.parseObject(String str)是将str转化为相应的JSONObject对象,其中str是“键值对”形式的json字符串,转化为JSONObject对象之后就可以使用其内置的方法,进行各种处理了。
JSONObject
put(String key, Object value)方法,在JSONObject对象中设置键值对在,在进行设值得时候,key是唯一的,如果用相同的key不断设值得时候,保留后面的值。
Object get(String key) :根据key值获取JSONObject对象中对应的value值,获取到的值是Object类型,需要手动转化为需要的数据类型。
int size():获取JSONObject对象中键值对的数量。
boolean isEmpty():判断该JSONObject对象是否为空。
containsKey(Object key):判断是否有需要的key值。
boolean containsValue(Object value):判断是否有需要的value值。
JSONObject getJSONObject(String key):如果JSONObjct对象中的value是一个JSONObject对象,即根据key获取对应的JSONObject对象。
JSONArray getJSONArray(String key) :如果JSONObject对象中的value是一个JSONObject数组,既根据key获取对应的JSONObject数组。
Object remove(Object key):根据key清除某一个键值对。由于JSONObject是一个map,它还具有map特有的两个方法。
Set<String> keySet() :获取JSONObject中的key,并将其放入Set集合中。
Set<Map.Entry<String, Object>> entrySet():在循环遍历时使用,取得是键和值的映射关系,Entry就是Map接口中的内部接口与String字符串转换。
toJSONString() /toString():将JSONObject对象转换为json的字符串。