1. JAVA引用与对象
1.1 知识点
- 下面这样一条语句,代表为dummyHead分配了内存空间,以及将dummyHead指向了新创建的对象:new ListNode();
理解为一句话搞了两个东西,这两个东西完全不同,一个在堆中new对象,一个在栈中存了引用操作这个对象
ListNode dummyHead = new ListNode();
- 注意下面这个,第一句就是已经给cur分配内存空间了,这个之前一直没有深刻印象。第二个是将cur指向 上面创建的对象
new ListNode();
相当于到现在有两个内存空间的两个引用,都指向了同一个对象,这两个引用都可以操作这个对象!
ListNode cur;
cur = dummyHead;
-
关键就在区别:
ListNode list; 这个list是引用,开辟了内存空间,存在栈中,像是气球的线,执行气球,操作气球。
new ListNode(); 这是创建对象!new创建的对象都存放在堆中,这就是气球!- 在JVM中的理解
1.2 使用leetcode中的删除链表中特定节点的题,加深理解
代码如下:
class Solution {
public ListNode removeElements(ListNode head, int val) {
//head也是一个节点,仅此而已,只不过head.next...通过这样的方式构成一个链表
ListNode dummyHead = new ListNode(); //实践上创建了一个节点,两个东西,一个是节点new的,另外一个是指针
dummyHead.next = head; //dummyHead 是引用,它指向的是刚刚new ListNode,现在操作刚刚new的对象,他的next指向了head节点。
ListNode curr = dummyHead; //重点:cur只是一个引用,它自己在栈中开辟了空间,cur现在和dummyHead都操作上面new的ListNode()
while(curr.next != null){
if(curr.next.val == val){
curr.next = curr.next.next;
}else{
//第一次curr.next的时候,引用现在指向不是之前new ListNode那个节点对象了,现在curr指向head(第一次next)
//但是dummyHead这个引用还是没变,依旧指向着之前new ListNode 这个对象。
curr = curr.next;
}
}
return dummyHead.next; //因为dummyHead引用从未改变,所以dummyHead.next就是第一个head节点
}
}
2、在回溯算法题中的相关引用问题
class Solution {
LinkedList<Integer> path = new LinkedList<>();
List<List<Integer>> result = new ArrayList<>();
int sum = 0;
public List<List<Integer>> combinationSum3(int k, int n) {
backtracking(k,n,1);
return result;
}
//1、确定回溯的返回值和参数
public void backtracking(int k, int n, int startIndex){
//2、确定终止条件
if(sum > n){return;}
if(path.size() == k){
if(sum == n){
//result.add(path);为什么不行?????????
result.add(new ArrayList(path));
}
return;
}
//3、单层逻辑
for(int i = startIndex; i <= 9; i++){
sum += i;//这是最要理解的地方,单层中结合数的结构还有下面的回溯来理解
path.add(i);
//取数,纵向递归,i+1是因为:例如取到2之后,应该从3开始遍历
backtracking(k,n,i+1);
//回溯
sum -= i;
path.removeLast();
}
}
}
result.add(path);为什么不行?而要使用result.add(new ArrayList(path));?
2.1 问题分析
path是一个引用(自己在栈内存中开辟了空间),由于回溯算法代码中,这个引用最开始是指向新创建的对象:new LinkedList<>();
(指向堆内存中的一个单元)。代码中,path指向的内容不变,都是new LinkedList<>();这个对象,但是,这个对象一直在改变,path永远指向最新状态的这个对象。因此在result.add(引用),到最后result里面无论在上面阶段add,都是引用指向的对象最终状态。看下面代码就理解了
@Test
public void testAlgorithm(){
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
path.add(1);
res.add(path);
path.add(2);
res.add(path);
res.forEach(data-> System.out.print(data+","));//[1, 2],[1, 2],
}
http://t.csdn.cn/rjtC2
3 byte数据结构和char数据结构的关系
- 在C或者Go中,byte和char类型之间的转换是通过ASCII编码进行的。ASCII是一种字符编码标准,它将每个字符映射到一个唯一的数字值。在ASCII编码中,字符 ‘A’ 对应的数值是 65,字符 ‘B’ 对应的数值是 66,以此类推。这些字符的ASCII值是0到127之间的整数。由于byte类型是无符号整数类型,它的取值范围也是0到255。因此,ASCII编码的字符可以直接存储在byte类型中,而不会有任何问题。
注意golang中没有char类型,存储字符如‘{’直接使用byte类型存储,对于字符’{‘,它在ASCII编码中对应的数值是123。因此,当我们将’{'存储到byte类型中时,byte变量的值将是123。
- golang中保存‘{’ 字符的方式。如果需要比较判断等等,全部都直接用byte对应的数值进行比较即可。
hash := map[byte]byte{')':'(', ']':'[', '}':'{'}
3.1 byte对应的数字转为char或者string类型
1. 首先,如果是java,直接强制类型转换即可(byte -> char)
byte b = 123;
char ch = (char) b; //输出 {
2. 如果是golang,由于golang中没有char类型,可以考虑转为string,byte转为string在go中有多种方式:**string(b)是将单个字节转换为字符串的方式,而string([]byte)是将整个字节数组转换为字符串的方式** (byte -> string)
var b byte = 123
str := string(b) //输出 {
-----------------
//先将byte类型的变量b放入一个byte切片中,然后使用[]byte{}创建一个只包含b的切片。
//接着,我们使用string()将该切片转换为string类型的变量str
var b byte = 123
str := string([]byte{b}) //输出{
- java 中byte -> String的做法 使用构造函数
//直接拼接会导致这样:
byte b = 123;
String str = "" + b; //输出 123 字符串
-------------------------------------------
//如果想要对应的字符,应该使用构造函数
byte b = 123;
String str = new String(new byte[] { b });