文章目录
- 零、引言
- 一、JAVA数据结构基础
- 1.0 数据类型概述
- 1.1 基本数据类型
- 零、引言
- 一、JAVA数据结构基础
- 1.0 数据类型概述
- 1.1 基本数据类型
- 1.2 包装类
- 1.3 基本类型和包装类型的区别
- 1.4 包装类型的缓存机制
- 1.5 equals() 和 ==
- 1.6 自动装箱拆箱
- 1.7 浮点数精度丢失
- 1.8 数值、字符转化、占位大小和缓冲池等代码解析
- 1.9 try-catch
- 二、 集合进阶&常用API
- 2.1 集合框架图
- 2.2 常用集合类和API
- 2.3 数据结构原理及适用场景
- 三、stream.filter collection
- 四、Gson等java转换小技巧
- 4.1 Gson Google 英文官网
- 4.2 [json转换对象方法](https://stackoverflow.com/questions/18544133/parsing-json-array-into-java-util-list-with-gson)
- 五、JAVA输入(刷题使用)
- Final、参考
零、引言
日常JAVA开发过程中需要用到的JAVA数据结构基础概念。
进阶集合框架、collection操作、常用API。
JAVA Gson等常用转化技巧
一、JAVA数据结构基础
1.0 数据类型概述
Java的数据类型分为:基本类型、引用类型。
String是引用类型,是lang包下的类。
1.1 基本数据类型
Java 中有 8 种基本数据类型。
4 种整数型:byte、short、int、long
2 种浮点型:float、double
1 种字符类型:char
1 种布尔型:boolean
Java数据类型所占存储空间大小与机器硬件结构无关,可移植性更高。
文章目录
- 零、引言
- 一、JAVA数据结构基础
- 1.0 数据类型概述
- 1.1 基本数据类型
- 零、引言
- 一、JAVA数据结构基础
- 1.0 数据类型概述
- 1.1 基本数据类型
- 1.2 包装类
- 1.3 基本类型和包装类型的区别
- 1.4 包装类型的缓存机制
- 1.5 equals() 和 ==
- 1.6 自动装箱拆箱
- 1.7 浮点数精度丢失
- 1.8 数值、字符转化、占位大小和缓冲池等代码解析
- 1.9 try-catch
- 二、 集合进阶&常用API
- 2.1 集合框架图
- 2.2 常用集合类和API
- 2.3 数据结构原理及适用场景
- 三、stream.filter collection
- 四、Gson等java转换小技巧
- 4.1 Gson Google 英文官网
- 4.2 [json转换对象方法](https://stackoverflow.com/questions/18544133/parsing-json-array-into-java-util-list-with-gson)
- 五、JAVA输入(刷题使用)
- Final、参考
零、引言
日常JAVA开发过程中需要用到的JAVA数据结构基础概念。
进阶集合框架、collection操作、常用API。
JAVA Gson等常用转化技巧
一、JAVA数据结构基础
1.0 数据类型概述
Java的数据类型分为:基本类型、引用类型。
String是引用类型,是lang包下的类。
1.1 基本数据类型
Java 中有 8 种基本数据类型。
4 种整数型:byte、short、int、long
2 种浮点型:float、double
1 种字符类型:char
1 种布尔型:boolean
Java数据类型所占存储空间大小与机器硬件结构无关,可移植性更高。
基本数据类型 字节数 包装类
布尔型 boolean 1 Boolean
字符型 char 2 Character
整型 byte 1 Byte
整型 short 2 Short
整型 int 4 Integer
整型 long 8 Long
浮点型 float 4 Float
浮点型 double 8 Double
1.2 包装类
包装类将基本数据类型包装转化为类的形式,具有面向对象的特征。
Java集合中只能放入包装类型,而不支持基本类型。
Java类型间的转换可以通过包装类的方法实现,基本数据类型没有类的属性方法。
所有整型包装类对象之间值的比较,全部使用 equals 方法比较。
对于 Integer var 在-128 至 127 之间的赋值,Integer 对象是在 IntegerCache.cache 产生, 会复用已有对象,这个区间内的Integer 值可以直接使用==进行判断.
但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,使用 equals 方法进行判断。
1.3 基本类型和包装类型的区别
默认值:包装类型不赋值就是 null ,基本类型有默认值且不是 null。
包装类型可用于泛型,而基本类型不可以。
包装类型属于对象类型,几乎所有对象实例都存在于堆中。
基本数据类型的局部变量存放在 Java 虚拟机栈中的局部变量表中。
基本数据类型的成员变量(未被 static 修饰 )存放在 Java 虚拟机的堆中。
1.4 包装类型的缓存机制
包装类型的大部分都用到了缓存机制来提升性能:节省创建对象的时间开销。对象可以自由共享。
Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据。
Character 创建了数值在 [0,127] 范围的缓存数据。
Boolean 直接返回 True or False。
Float,Double 并没有实现缓存机制。
如果超出对应范围会创建新的对象,缓存的范围区间的大小只是在性能和资源之间的权衡。
包装器类提供了对象的缓存,String类提供了常量池,都有final修饰,对象一经创建后不可修改。
1.5 equals() 和 ==
==
- 对于基本数据类型来说,== 比较的是值。
- 对于引用数据类型来说,== 比较的是对象的内存地址。
- == 运行速度比equals()快,因为==只是比较引用。
equals()
- equals() 不能用于判断基本数据类型的变量,只能用来判断两个对象是否相等。
- equals()方法存在于Object类中,而Object类是所有类的直接或间接父类,因此所有的类都有equals()方法。
- 如果类没有重写 equals()方法:等价于通过“==”比较这两个对象,使用的默认是 Object类equals()方法。是否为同一内存地址。
- 如果类重写了 equals()方法 :一般会重写 equals()方法来比较两个对象中的属性是否相等;若它们的属性相等,则返回 true(即,认为这两个对象相等)。
- String 中的 equals 方法是被重写过的,比较的是对象的值。
- 当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。
String a = new String("ab"); // a 为一个引用
String b = new String("ab"); // b为另一个引用,对象的内容一样
String aa = "ab"; // 放在常量池中
String bb = "ab"; // 从常量池中查找
System.out.println(aa == bb);// true
System.out.println(a == b);// false
System.out.println(a.equals(b));// true
System.out.println(42 == 42.0);// true
1.6 自动装箱拆箱
装箱:将基本类型用它们对应的引用类型包装起来;调用了包装类的valueOf()方法。
拆箱:将包装类型转换为基本数据类型;调用了 intValue()方法。
如果频繁拆装箱的话,也会严重影响系统的性能。应该尽量避免不必要的拆装箱操作。
public static void WrapTest1() {
// 自动装箱,等效于 Integer num = Integer.valueOf(100);
Integer num = 100;
// 自动拆箱,等效于 int num2 = num.intValue();
int num2 = num;
// valueOf() 方法返回对应包装类实例
System.out.println("-----valueOf()-----");
Integer a =Integer.valueOf(9); // 将int转为Integer包装类对象
Double b = Double.valueOf(5);
Float c = Float.valueOf("80"); // 将字符串转为Float包装类对象
Integer d = Integer.valueOf("444",16); // 使用 16 进制
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
}
结果:
-----valueOf()-----
9
5.0
80.0
1092
1.7 浮点数精度丢失
浮点数运算的时候会有精度丢失的风险。计算机使用有限的宽度表示一个数字,无限循环的小数存储在计算机时,只能被截断。
BigDecimal 可以实现对浮点数的运算,不会造成精度丢失。
BigInteger 内部使用 int[] 数组来存储任意大小的整形数据。
1.8 数值、字符转化、占位大小和缓冲池等代码解析
// 精度测试
public static void intTest() {
System.out.println(5/2);
double x = 1.0 / 10;
double y = 1 - 9.0 / 10;
System.out.println(x);
System.out.println(y);
// 四舍五入
double d = 2.6;
int n = (int) (d + 0.5);
System.out.println(n);
double e = 2.4;
int m = (int) (e + 0.5);
System.out.println(m);
char c3 = '\u0041';
System.out.println(c3);
double d = 12900000;
System.out.println(d);
double e = 3.1415926;
System.out.printf("%.2f\n", e);
System.out.printf("%.4f\n", e);
int n = 12345000;
System.out.printf("n=%d, hex=%08x \n", n, n);
System.out.printf("%%%d", n);
}
// 基本数据类型与字符串的转换
public static void WrapTest3() {
// 基本数据类型转换为String
String str1 = String.valueOf(111);
String str2 = 222 + "";
String str3 = Integer.toString(333);
// 字符串转换成基本数据类型
int a = Integer.parseInt("111");
// 字符串转换成包装类
Integer b = Integer.valueOf("222");
// 包装类型转换为字符串类型
String str4 = String.valueOf(Integer.valueOf(444));
}
1.9 try-catch
try-catch用来捕获代码段的异常并做出处理
try-catch代码块分两块,第一块是try{} ,第二块是catch(exception的引用){}。
try-catch一般放在循环放外。
try-catch,try即尝试,尝试能不能正常的走完整个作用域,如果不能则抛出一个异常。所以在try块里经常放上可能会抛出异常的程序段。而catch就是处理try里抛出来的异常,其中catch的参数列表接收的是一个异常的引用,是throw抛出来的异常的引用。
try-catch可以嵌套使用,以下是一个try-catch嵌套使用的例子:
public static void main(String[] args) {
try {
System.out.println("**********************外层try**********************");
errorMethod();
} catch (Exception e) {
System.out.println("**********************外层catch" + e + "**********************");
} finally {
System.out.println("**********************外层finally**********************");
}
}
private static void errorMethod() {
try {
System.out.println("**********************内层try**********************");
int i = 0;
int a = 100 / i;
} catch (Exception e) {
System.out.println("**********************内层catch" + e + "**********************");
} finally {
System.out.println("**********************内层finally**********************");
}
执行顺序:
- 内层A,E处抛出异常:由外层catch块捕获,并执行外层finally ;
- 内层B处抛出异常,且有一合适内层catch捕获在:执行内层finally,后执行E处 ;
- 内层B处抛出异常,但内层catch块没有合适处理程序:执行内层finally,搜索外层catch,找合适的,执行外层finally,此时不会执行E ;
- 内层C处抛出异常在:退出内层catch块,执行内层finally,搜索外层catch,找到合适,执行外层finally ;
- 内层D处抛出异常在:退出内层finally块,搜索外层catch,找到合适,执行外层finally
总结:
-
try-catch 嵌套内层catch 可以捕获异常时,外层catch不会执行,但finally (多用于IO关闭)都会执行。
-
try-catch一般用在最上层的程序里,可以配合throws和throw再将异常抛给用户,这种情况会使上层代码中断。也可以不选择抛出,这种上层代码会继续运行。
-
被调用的方法如果有异常的可能可以通过throws抛给上层处理,不加try catch的情况如下会自动往上抛,加了try catch需要如上通过throw抛给上层程序。
二、 集合进阶&常用API
2.1 集合框架图
从上面的集合框架图可以看到,Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。Collection 接口又有 3 种子类型,List、Set 和 Queue,再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap 等等。
集合框架是一个用来代表和操纵集合的统一架构。所有的集合框架都包含如下内容:
-
接口:是代表集合的抽象数据类型。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式操作集合对象
-
实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap。
-
算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序,这些算法实现了多态,那是因为相同的方法可以在相似的接口上有着不同的实现。
除了集合,该框架也定义了几个 Map 接口和类。Map 里存储的是键/值对。尽管 Map 不是集合,但是它们完全整合在集合中。
Java 集合框架提供了一套性能优良,使用方便的接口和类,java集合框架位于java.util包中, 所以当使用集合框架的时候需要进行导包。
2.2 常用集合类和API
1:数组
定义
int len = 5;
int[] arr = new int[len];
1
2
赋值
for (int i = 0; i < arr.length; i++) {
Scanner scanner = new Scanner(System.in);
arr[i] = scanner.nextInt();
}
1
2
3
4
遍历输出
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
1
2
3
常用API之排序
Arrays.sort(arr);
1
2.List
定义
List<Integer> list = new ArrayList<>();
1
赋值
for (int i = 0; i < 5; i++) {
int nums = in.nextInt();
list.add(nums);
}
1
2
3
4
遍历
遍历输出 它的大小是 size() 区别数组的 length 区别字符串的 length()
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i)+" ");
}
1
2
3
API调用之sort升序
注意o1.conpareTo(o2)
list.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);//这里还可以用 o1 - o2 这个是等价的
}
});
1
2
3
4
5
6
conpareTo的源码:
其实就是3目运算符
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
1
2
3
API调用之sort降序
** 注意o2.compareTo(o1)**
list.sort(new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);//这里还可以用 o2 - o1 这个是等价的
}
});
1
2
3
4
5
6
API调用之按照对象的某个字段排序
关于这个我们给出一个情景好记忆。
比如我们要给一个班级数学成绩排序,数学成绩相同的话,那么我们就按照名字的字典序进行排序。
输入:5
wyj 100
aaa 90
abc 100
bbb 70
ccc 30
输出: abc 100
wyj 100
aaa 90
bbb 70
ccc 30
public class textList {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
ArrayList<Student> list = new ArrayList<>();
System.out.print("请输入学上的个数:");
int studentNums = in.nextInt();
for (int i = 0; i < studentNums; i++) {
String sname = in.next();//nextLine()输入的是一行数据会包含空格 eg wyj 100
int sgrade = in.nextInt();
list.add(new Student(sname,sgrade));
}
list.sort(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
if (o1.getGrate() == o2.getGrate()) {
return o1.getName().compareTo(o2.getName());
}
return o2.getGrate()-(o1.getGrate());
}
});
for (int i = 0; i < studentNums; i++) {
System.out.println(list.get(i).toString());
}
}
}
class Student {
private String name;
private int grate;
public Student(String name, int grate) {
this.name = name;
this.grate = grate;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getGrate() {
return grate;
}
public void setGrate(int grate) {
this.grate = grate;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", grate=" + grate +
'}';
}
}
3:Map
定义
Map<String,Integer> map = new HashMap<>();
1
赋值
for (int i = 0; i < 3; i++) {
String name = in.next();
int grade = in.nextInt();
map.put(name,grade);
}
遍历
map提供的get方法是根据key值来获取 value 值
for (String s : map.keySet()) {
System.out.println(s + " " + map.get(s));
}
常用API之判断某个值是否存在
map.containsKey("wyj")
常用API之移除某个key
map.remove("wyj")
Entry
由于Map中存放的元素均为键值对,故每一个键值对必然存在一个映射关系。
Map中采用Entry内部类来表示一个映射项,映射项包含Key和Value (我们总说键值对键值对, 每一个键值对也就是一个Entry)
Map.Entry里面包含getKey()和getValue()方法
Iterator<Map.Entry<Integer, Integer>> it=map.entrySet().iterator();
while(it.hasNext()) {
Map.Entry<Integer,Integer> entry=it.next();
int key=entry.getKey();
int value=entry.getValue();
System.out.println(key+" "+value);
}
entrySet
entrySet是 java中 键-值 对的集合,Set里面的类型是Map.Entry,一般可以通过map.entrySet()得到。
entrySet实现了Set接口,里面存放的是键值对。一个K对应一个V。
用来遍历map的一种方法。
Set<Map.Entry<String, String>> entryseSet=map.entrySet();
for (Map.Entry<String, String> entry:entryseSet) {
System.out.println(entry.getKey()+","+entry.getValue());
}
4:Set
定义
HashSet<Integer> set = new HashSet<>();
1
赋值
for (int i = 0; i < 3; i++) {
int nums = in.nextInt();
set.add(nums);
}
遍历
这里的遍历的话 是可以去重的和升序的
for (int nums:set) {
System.out.println(nums);
}
常用API之判断某个元素是否存在
set.contains(元素)
1
常用API之移除某个key
set.remove(1)
1
常用API之清空容器
set.clear();
1
5.栈
//这是一个双端队列
ArrayDeque<Character> deque = new ArrayDeque<>();
//在栈中push就是往容器尾部插入一个值
deque.push('a');
deque.push('b');
deque.push('c');
deque.push('d');
//访问栈顶元素
System.out.println(deque.peek());
//删除一个元素
deque.pop();
System.out.println(deque.peek());
6:队列
//这是一个双端队列
ArrayDeque<Integer> deque = new ArrayDeque<>();
//用add的话表示就是取元素顺序时候就是先进先出
deque.add(1);
deque.add(2);
deque.add(3);
//我们用 peek()进行访问 访问的是队列首部元素
System.out.println(deque.peek());
//我们用 pool()表示的就是移除队列首部元素
deque.poll();
System.out.println(deque.peek());
//访问队尾元素
System.out.println(deque.getLast());
//移除队尾元素
deque.removeLast();
System.out.println(deque.getLast());
2.3 数据结构原理及适用场景
具体请参考:https://www.runoob.com/java/java-collections.html
三、stream.filter collection
Java8及以上版本中,使用stream().filter()来过滤一个List对象,查找符合条件的对象集合。
import lombok.Data;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class TestStreamFilter {
public static void sorted() {
List<Integer> list = Arrays.asList(5, 4, 3, 2, 7, 1, 6, 9, 8);
//过滤出大于5的数值
List<Integer> filterList = list.stream().filter(x -> x > 5).collect(Collectors.toList());
System.out.println("原始数组:" + list);
System.out.println("过滤数组:" + filterList);
System.out.println();
List<Person> personList = new ArrayList<>();
personList.add(new Person("张三", 16, 181));
personList.add(new Person("李四", 17, 180));
personList.add(new Person("王五", 16, 179));
personList.add(new Person("张明", 18, 180));
personList.add(new Person("李威", 16, 190));
personList.add(new Person("王鹏", 15, 188));
personList.add(new Person("王莉", 17, 177));
personList.add(new Person("王鸥", 19, 180));
//年龄18岁及以上,身高180的人
List<Person> filterPList = personList.stream().filter(s -> s.getAge() >= 18 && s.getHeight() == 180).collect(Collectors.toList());
printPerson(filterPList);
}
public static void printPerson(List<Person> userList) {
System.out.println("【姓名】\t【年龄】\t【身高】");
System.out.println("-----------------------");
userList.forEach(s -> System.out.println(s.toString()));
System.out.println(" ");
}
public static void main(String[] args) {
sorted();
}
}
@Data
class Person {
private String name;
private Integer age;
private Integer height;
public Person(String name, Integer age, Integer height) {
this.name = name;
this.age = age;
this.height = height;
}
public String toString() {
String info = String.format("%s\t\t%s\t\t%s\t\t\t", this.name, this.age.toString(), this.height.toString());
return info;
}
}
对应输出:
原始数组:[5, 4, 3, 2, 7, 1, 6, 9, 8]
过滤数组:[7, 6, 9, 8]
【姓名】 【年龄】 【身高】
-----------------------
张明 18 180
王鸥 19 180
四、Gson等java转换小技巧
4.1 Gson Google 英文官网
- Gson User Guide
- Gson – Parse JSON Array to Java Array or List–概念示例和代码
4.2 json转换对象方法
Definitely the easiest way to do that is using Gson’s default parsing function fromJson().
There is an implementation of this function suitable for when you need to deserialize into any ParameterizedType (e.g., any List), which is fromJson(JsonElement json, Type typeOfT).
In your case, you just need to get the Type of a List and then parse the JSON array into that Type, like this:
import java.lang.reflect.Type;
import com.google.gson.reflect.TypeToken;
JsonElement yourJson = mapping.get("servers");
Type listType = new TypeToken<List<String>>() {}.getType();
List<String> yourList = new Gson().fromJson(yourJson, listType);
In your case yourJson is a JsonElement, but it could also be a String, any Reader or a JsonReader.
You may want to take a look at Gson API documentation.
五、JAVA输入(刷题使用)
1: 常规的输入
Scanner in = new Scanner(System.in);
System.out.println("请输入你的年龄:");
int age = in.nextInt();//整数类型的输入方式
System.out.println("请输入你的身高:");
double height = in.nextDouble();//小数类型的输入方式
2:关于其他输入符在nextLine()之前用吃掉回车符的问题解决
当比如我们在输入的是时候前面用了 nextInt();后面的话用了nextLine()的话,其会吃掉回车符,导致我们无法正常输入
那么我们的解决办法有两种
将nextLine()改为next(),但是呢那么你就无法输入带空格的字符了
将nextLine()的前面再加上nextLine(),这样就可以帮助我们吃掉回车符,那么我们正常的输入就不会有问题了。
请看示例:
Scanner in = new Scanner(System.in);
System.out.println("请输入你的年龄:");
int age = in.nextInt();//整数类型的输入方式
System.out.println("请输入苹果的英文:");
in.nextLine();//nextLine()会吃掉回车符,这样的话 我们下面就可以正常输入了
String s1 = in.nextLine();//nextLine是可以输入带空格的数据的。
System.out.println("请输入你的身高:");
double height = in.nextDouble();//小数类型的输入方式
3: 常见输入之我们输入一串数到容器中
这个是我们常用的之一,当题目给出一串数的话,我们往往是要将其存放在容器当中的,那么的话我们就可以方便操作了
Scanner in = new Scanner(System.in);
int[] arr = new int[10];
for (int i = 0; i < 10; i++) {
arr[i] = in.nextInt();
}
for (int i : arr) {
System.out.print(i+ " ");
}
Final、参考
- JAVARunoob集合框架
- 【Java】基本数据类型与包装类
- 用Java刷算法题的常用数据结构(C++转Java)
- Java 中 try-catch,throw和throws的使用