CompileMind

compile code, compile mind

0%

tr命令

tr命令可以将输入的数据中的某些字符做替换或者是作删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
tr [-ds] STR
d: 删除输入数据的中的STR
s: 替换重复的字符
#
last | tr '[a-z]' 'A-Z'
将last输出的数据中的所有小写字符替换为大写字符
SPPU UUZ1 TVF MBS 13 18:45 TUJMM MPHHFE JO
SFCPPU TZTUFN CPPU 3.10.0-693.17.1. TVF MBS 13 18:45 - 18:47 (00:01)
SPPU UUZ1 TVF MBS 13 10:55 - 13:15 (02:20)
SFCPPU TZTUFN CPPU 3.10.0-693.17.1. TVF MBS 13 10:54 - 18:47 (07:52)
SPPU UUZ1 MPO MBS 12 18:33 - 19:35 (01:02)
...

cat /etc/passwd | tr -d ':'
将cat /etc/passwd输出的数据中的':'全部删除
# output
rootx00root/root/bin/bash
binx11bin/bin/sbin/nologin
daemonx22daemon/sbin/sbin/nologin
admx34adm/var/adm/sbin/nologin
lpx47lp/var/spool/lpd/sbin/nologin
...

col命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
col [-xb]
-x: 将tab键替换为等长的空个
-b: 在文字内由反斜杠时,仅保留反斜杠后接的那个字符

cat -A ~/.bashrc
# 使用cat -A可以讲输出中所有的特殊按键
# output
...
# Source global definitions$
if [ -f /etc/bashrc ]; then$
^I. /etc/bashrc$
fi$
# 注意这里有个^I就是tab字符。

cat -A ~/.bashrc | col -x
# output
# Source global definitions$
if [ -f /etc/bashrc ]; then$
. /etc/bashrc$
# tab字符不再出现

join命令

用于对两个文件按照某一个字符或者字段进行按行连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
join [-ti12] file1 file2
-t: 选择分割字符,并且对比“第一个字段”的数据,如果两个文件相同,则将两条数据连成一行,并将第一个字段放在最前
-i: 忽略大小写
-1: 表示第一个文件
-2: 表示第二个文件

# 例1
head -n 3 /etc/passwd /etc/shadow
# 先查看这两个文件前三行数据
==> /etc/passwd <==
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

==> /etc/shadow <==
root:<密码太长,我忽略了方便查看>:17593:0:99999:7:::
bin:*:17110:0:99999:7:::
daemon:*:17110:0:99999:7:::

join -t ':' /etc/passwd /etc/shadow | head -n 3
# output
root:x:0:0:root:/root:/bin/bash:<密码太长,我忽略了方便查看>:17593:0:99999:7:::
bin:x:1:1:bin:/bin:/sbin/nologin:*:17110:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin:*:17110:0:99999:7:::
# 我们可以看到,按照':'分割,并且默认一第一个字段进行连接

# 例2
我们知道/etc/passwd中第四个字段是GID,而/etc/group中第三个字段是GID,我们就可以像如下进行整合:
join -t ':' -1 4 /etc/passwd -2 3 /etc/group | head -n 3
# output
0:root:x:0:root:/root:/bin/bash:root:x:
1:bin:x:1:bin:/bin:/sbin/nologin:bin:x:
2:daemon:x:2:daemon:/sbin:/sbin/nologin:daemon:x:
# 我们可以看到,将我们需要的字段提到了最前

paste命令

1
2
3
4
5
6
7
8
直接讲两个文件中的数据按行连接
paste [-d] file1 file2
-d: 设定每行数据连接的字符,默认为tab
paste /etc/passwd /etc/group | head -n 3
# output
root:x:0:0:root:/root:/bin/bash root:x:0:
bin:x:1:1:bin:/bin:/sbin/nologin bin:x:1:
daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon:x:2:

expand命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
expand [-t] file
-t: 后面接数字,代表了将一个tab替换为多少个空格键
#
cat -A ~/.bashrc
# 使用cat -A可以讲输出中所有的特殊按键
# output
...
# Source global definitions$
if [ -f /etc/bashrc ]; then$
^I. /etc/bashrc$
fi$
注意看有个^I,是tab符号
cat -A ~/.bashrc | expand -t 10 -(标准输入) | cat -A
# output
...
# Source global definitions$
if [ -f /etc/bashrc ]; then$
. /etc/bashrc$
fi$
我们可以看到原先的tab变为了10个空格

数据流重定向

1
2
3
4
标准输入(stdin):代码为0,使用<或<<;
标准输出(stdout):代码为1,使用>或>>;
标准错误输出(stderr):代码为2,使用2>或2>>;
>:覆盖的方式,>>:追加的方式

如果想要一般输出与错误输出同时输入到某一个文件,如果采取如下的方式进行输出是错误的:

1
输出数据  1> list 2> list

如果按照上面的方式输出到list文件中时而没有采用特殊的语法,会因为两个输出进程的同步问题,导致正确的数据与错误的数据可能会交叉的输入到list文件中。正确的方式应该如下:

1
2
3
输出数据 > list 2>&1
# 或者是
输出数据 &> list

命令执行&& ||

1
2
3
4
5
6
7
cmd1 && cmd2
若cmd1执行完毕且正确执行($?==0),则执行cmd2
若cmd1执行完毕且错误执行($?!=0),则不执行cmd2

cmd1 || cmd2
若cmd1执行完毕且执行正确($?==0),则不执行cmd2
若cmd1执行完毕且执行错误($?!=0),则执行cmd2

cut命令

cut命令按行数据进行处理,常用的方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#参数 -d -f(组合使用)
输出数据 | cut -d '分个字符' -f fields
#
str=ni:hao:ma:?
echo $str | cut -d ':' -f 2
表示将echo出的str字符串按照':'字符分割,且取第2个字段
得到的结果是
hao
# 补充
-f 1,3 代表取第1和第3字段,输出 ni:man
-f 1-3 取1到3字段,输出 ni:hao:ma

# 参数 -c
输出数据 | cut -c 字符范围
#
str=hello
echo $str | cut -c 1
输出
h
# 补充
-c 1-,输出 hello
-c 1-3,输出 hel

sort命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
head -4 /etc/passswd
# output
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
我们可以看到并没有按照首字母排序

head -4 /etc/passwd | sort
# output
adm:x:3:4:adm:/var/adm:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
root:x:0:0:root:/root:/bin/bash
我们可以看到已经按照首字母排序了

同样,我们可以指定想按照哪一个字段来排序,
head /etc/passwd | sort -t ':' -k 3
# 不看前4行了,准备输出所有行
# 将输出按照类型':'分割(-t ':'),并且取第3个字段(-k 3)
# 然而此时的字段依然是按照字符进行,如本测试机上输出的结果注意看第二行:
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
# 注意第三个字段,11跑到了2前面去了,因为字符串11排在2前面
此时我们需要加上 -n 参数提示按照数字进行
head /etc/passwd | sort -t ':' -k 3 -n

last命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 该命令用来列出目前与过去登录系统的用户相关信息
last
# output
root tty1 Mon Mar 12 18:33 still logged in
reboot system boot 3.10.0-693.17.1. Mon Mar 12 18:33 - 19:02 (00:29)
root tty1 Sat Mar 10 20:18 - 20:18 (00:00)
reboot system boot 3.10.0-693.17.1. Sat Mar 10 20:18 - 20:18 (00:00)
root tty1 Fri Mar 9 19:10 - 20:50 (01:40)
...
其中:
第一列:用户名
第二列:终端位置。(pts/0通过ssh或者telnet远程连接的用户,tty:直接连接到计算机或者本地用户)
第三列:登陆IP或者内核(看到0.0或者什么都没有,意味着用户通过本地终端连接,除了重启,内核版本会显示在状态中)

第四列:开始时间(如:sun apr 3 :四月三号星期天)
第五列:结束时间(still login in 还未退出,down:直到正常关机,crash:直到强制关机)
第六列:持续时间

uniq命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
last | cut -d ' ' -f 1 | sort | uniq
# 先取用户名,然后排序,最后去重
# output
reboot
root
wtmp
zhen
# 加上 -c 显示统计
last | cut -d ' ' -f 1 | sort | uniq -c
# output
1
27 reboot
26 root
1 wtmp
3 zhen

务必注意,uniq命令是通过叠加去重相邻的字符串,如果你不首先进行排序,那么会出现下面的情况:

1
2
3
4
5
6
7
8
9
10
11
12
      1 root
1 reboot
1 root
1 reboot
1 root
1 reboot
1 root
1 reboot
1 zhen
1 root
1 reboot
...

wc命令

1
2
3
4
5
6
7
8
wc [-lwm]
-l: 仅列出行
-w: 仅列出多少个英文单词
-m: 仅列出多少个字符
head /etc/passwd | wc
# output
10 10 385
# 分别代表行数,词数,字符数(这里10个“词”应该是因为每一行没有空格的原因,wc统计是按空格来分词的)

tee双向重定向

由前面的数据流我们可以知道,我们在将数据定向时,如果不采取特殊的操作,数据要么输出到屏幕,要么输出到文件或者是设备中,没有办法,既输出到屏幕有输出到文件中;又或者是,我们想要对数据进行处理存放到一个文件中,但是同时对原始数据又存到另一个文件中。使用tee命令,我们就可以做到。

例如,我们使用last命令首先要把数据存放到last.log中,同时要对用户去重并输出到屏幕上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
last | tee [-a 追加] last.log | cut -d ' ' -f 1 | sort | uniq
# output

reboot
root
wtmp
zhen
# 同时我们打开last.log文件可以看到没有做任何处理的原始数据
root tty1 Mon Mar 12 18:33 still logged in
reboot system boot 3.10.0-693.17.1. Mon Mar 12 18:33 - 19:29 (00:56)
root tty1 Sat Mar 10 20:18 - 20:18 (00:00)
reboot system boot 3.10.0-693.17.1. Sat Mar 10 20:18 - 20:18 (00:00)
root tty1 Fri Mar 9 19:10 - 20:50 (01:40)
...

前情提要,如果系统中存在两个都实现了同一接口的类,Spring在进行@Autowired自动装配的时候,会选择哪一个?如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 一下两个类均被标记为bean
@Component
public class CD implements Playable {
@Override
public void play() {
System.out.println("CD is playing...");
}
}
@Component
public class Video implements Playable {
@Override
public void play() {
System.out.println("Video is playing...");
}
}

//配置类仅打开自动扫描
@Configuration
@ComponentScan(basePackages = "zhen"
public class MyConfig {
}

//测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MyConfig.class)
public class MyConfigTest {
@Autowired
Playable playable;
@Test
public void checkNULL() {
Assert.assertNotNull(playable);
}
}

此时再次运行测试类会发现,FAILD并且报错:

Unsatisfied dependency expressed through field ‘playable’; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type ‘zhen.Playable’ available: expected single matching bean but found 2: CD,video // 找到了两个都bean都能匹配

自动装配歧义性问题

上面的异常就是出现了歧义性。Spring为我们扫描了我们代码中的bean(这个部分是没有问题的),但是,在自动装配的过程中却由于歧义性而报错,并且,造成这样的歧义性还有由于Autowired这个注解仅仅按照类型进行装配——上面的CD与Video都实现了Playable接口,Autowired注解仅告诉Spring在测试类中的playable接受一个Playable类型的对象但是这里有两个bean:CD、video都是Playable类型的,所以Spring不知道。

为了解决这个问题,我们需要通过一定的手段来限定:

1
2
声明首选的bean
限定自动转配的bean

声明首选的bean

根据名字我们很容易理解,就是声明在有歧义性情况下,Spring到底选择哪一个bean来装配。方式就是在bean组件下添加@Primary注解,例如在原先的CD的@Component下加上首选注解,再次运行测试代码,PASS。但是,这种方式通常只在同类型bean较少的或者是系统简单的情况使用,而且还存在一个情况:假如目前有两位开发人员,在各自的环境编写bean,他们都希望自己的bean是Primary的,都加该注解,实际上还是会报错,因为系统现在同样有两个Primary bean,Spring还是不能判断选择哪一个bean注入。

限定自动装配的bean——@Qualifier注解

首先,我们可以通过在@Component中加入字符串来更明确的指定bean id而不是使用Spring的默认bean id策略。就像如下:

1
2
3
4
5
6
7
8
@Component("myCD")
public class CD implements Playable {
// ...
}
@Component("myVideo")
public class Video implements Playable {
// ...
}

当这样指定以后,我们在自动转配的地方,使用@Qualifier(“指定id”)来限定我们要注入的确定的bean:

1
2
3
4
5
...
@Autowired
@Qualifier("myCD")
Playable playable;
...

再次运行不会报错。

关于@Qualifier,最佳的情形应该是来标记bean特性。但是,如果多个bean都有相同的特性,都是用了相同的标记的@Qualifier注解,那么同样又会出现歧义性问题。所以我们又要添加新的@Qualifier注解来进一步限定,这样做没有问题,但是Java语法规定,不允许在同一条目上重复出现相同类型的多个注解。你不能这么做:

1
2
3
4
5
6
// 编译器会报错
@Qualifier("myCD")
@Qaulifier("JayChou")
public class CD implements Playable {
...
}

为了结局这样的问题,我们可以创建自己的注解:

1
2
3
4
5
6
7
8
9
10
@Target({ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.TYPE, ElementType.METHOD}) //字段注解  
@Retention(RetentionPolicy.RUNTIME) //在运行期保留注解信息
@Qualifier // 需要使用@Qualifier注解来限定
public @interface MyCD {
}
@Target({ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface JayChou {
}

如此定义了注解以后,我们就可以在原先的@Component下如下定义:

1
2
3
4
5
6
@Component
@MyCD
@JayChou
public class CD implements Playable {
...
}

并且在测试类下如下声明:

1
2
3
4
@Autowired
@MyCD
@JayChou
Playable playable;

测试通过!

Spring中的Bean是一个很重要的概念。Spring作为一个Bean容器,它可以管理对象和对象之间的依赖关系,我们不需要自己建立对象,把这部分工作全部转交给容器完成,具有低耦合,对代码没有侵略性。

Linux是一个多用户系统,但是对于一个多用户共存的系统中,当然不能够出现用户相互越权等一系列的安全问题,所以如何正确的管理账户成为了Linux系统中至关重要的一环。

前期准备

1.配置hostname(可选,了解)

在CentOS中,有三种定义的主机名:静态的(static),瞬态的(transient),和灵活的(pretty)。“静态”主机名也称为内核主机名,是系统在启动时从/etc/hostname自动初始化的主机名。“瞬态”主机名是在系统运行时临时分配的主机名,例如,通过DHCP或mDNS服务器分配。静态主机名和瞬态主机名都遵从作为互联网域名同样的字符限制规则。而另一方面,“灵活”主机名则允许使用自由形式(包括特殊/空白字符)的主机名,以展示给终端用户(如Linuxidc)。

在CentOS7以前,配置主机的静态hostname是在/etc/sysconfig/network中配置HOSTNAME字段值来配置,而CentOS7之后若要配置静态的hostname是需要在/etc/hostname中进行。

进入Linux系统,命令行下输入hostname可以看到当前的hostname,而通常默认的hostname是local.localadmin。

本次试验环境在CentOS7下,所以我们编辑/etc/hostname文件,试验hostname为:hadoop.w4ng,填入其中,重启Linux,可以看到已经生效。
hostname.png

2.配置静态IP

同样,在CentOS7以后,其网卡配置已经有原先的/etc/sysconfig/network/network-scripts下面的ifcfg-eth0等改名为乐ifcfg-enpXsY(en表示ethnet,p表示pci设备,s表示soket)
ll-network-scripts.png
本人这里有两个ifcfg文件是因为配置了两块网卡分别做NAT以及与虚拟机Host-Only两个功能,实现双网卡上网

打开ifcfg-enp0s8,配置如下:

1
2
3
4
5
6
7
DEVICE=enp0s8 #设备名
HWADDR=08:00:27:10:6B:6B #硬件地址
TYPE=Ethernet #类型
BOOTPROTO=static #静态IP(必备)
IPADDR=192.168.56.88 #IP地址
NETMASK=255.255.255.0 #子网掩码
ONBOOT=yes #设备开机自动启动该网卡

3.配置hosts

打开/etc/hosts
配置为如下的:

1
2
3
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.56.88 hadoop.w4ng

配置hosts的理由是后期hadoop配置中相关的主机填写我们都是使用域名的形式,而IP地址与域名的转换在这里进行查询(还有DNS,但是这里不讨论)。

4.关闭防火墙

CentOS7与6的防火墙不一样。在7中使用firewall来管理防火墙,而6是使用iptables来进行管理的。当然,我们可以卸载7的firewall安装6的iptables来管理。本人就切换回了6的防火墙管理方式。

1
2
[root@localhost ~]#servcie iptables stop  # 临时关闭防火墙
[root@localhost ~]#chkconfig iptables off # 永久关闭防火墙

5.JDK与Hadoop的安装

下载JDK8
下载Hadoop3-binary
下载完毕将文件传到主机中。

在/usr/local/下创建java文件夹,并将JDK解压至该文件夹下。
在根目录下创建/bigdata文件夹,并将Hadoop解压至其中。

1
解压命令 tar -zxv -f [原压缩文件.tar.gz] -C [目标文件夹目录] # 实际命令没有中括号,其次,命令参数重-z对应gz压缩文件,若为bz2则使用-j

在JDK解压完成后,在~/.bash_profile中配置环境变量 点这里看/etc/bashrc、/.bashrc、/.bash_profile关系

1
2
export JAVA_HOME=/usr/local/java/jdkx.x.x_xxx
export PATH=$PATH:$JAVA_HOME/bin

配置完成,保存退出并 source ~/.bash_profile

hadoop无需配置环境变量

6.配置hadoop

在hadoop的home下,进入etc文件夹,有五个主要的文件需要进行配置:

1
2
3
4
5
hadoop-env.sh
core-site.xml
hdfs-site.xml
mapred-site.xml
yarn-site.xml

基本配置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
1.配置 hadoop-env.sh
export JAVA_HOME
#找到该处,填写上上面配置的JAVA_HOME,因为hadoop是基于Java的,需要Java的环境

2.配置 core-site.xml
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://hostnameXXX:9000</value>
</property>
<!-- 配置hadoop文件系统目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/bigData/tmp</value>
</property>
</configuration>

3.配置 hdfs-site.xml
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>

4.配置 mapred-site.xml
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>

5.配置 yarn-site.xml
<configuration>
<property>
<name>yarn.resourecemanager.hostname</name>
<value>hostnameXXX</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
</configuration>

然后配置相关服务启动过程中需要的配置变量:
进入${HADOOP_HOME}/sbin中,在start-dfs.sh与stop-dfs.sh中添加字段:

1
2
3
4
HDFS_DATANODE_USER=root
HDFS_DATANODE_SECURE_USER=hdfs
HDFS_NAMENODE_USER=root
HDFS_SECONDARYNAMENODE_USER=root

在start-yarn.sh与stop-yarn.sh中添加:

1
2
3
YARN_RESOURCEMANAGER_USER=root
HADOOP_SECURE_DN_USER=yarn
YARN_NODEMANAGER_USER=root

配置完成以后,进行hadoop的文件系统格式化,执行

1
${HADOOP_HOME}/bin/hdfs namenode -format

最后是启动服务:

1
执行${HADOOP_HOME}/sbin/start-all.sh  # 他会去调用start-dfs.sh与start-yarn.sh

根据配置中我们都是配置的root用户,显然需要我们以root身份进行,且过程中需要root密码。当然,通过ssh免密可以方便很多。启动完成以后,命令行中使用jps命令打印Java进程,会看到下图五个进程(忽略Jps进程):
jps.png
当然,Hadoop在服务启动以后以提供web端:

1
2
3
4
visit hdfs manage page
xxx.xxx.xxx.xxx:50070
visit yarn manage page
xxx.xxx.xxx.xxx:8088

最近开始学习Spring,在看《Spring实战4th》3.3“处理自动装配的歧义性”那一部分时,书上提到(也从网上看到了类似的用法):
通过在一个类上加注@Component以及@Qualifier(“x”)可以为其配置限定符来标识区分同一个接口下的不同实现类,用以在需要进行@Autowired自动装配的地方使用@Qualifier(“x”)来指定特定的实现类对象bean。

尽管从Mac的Terminal可以看出,macOS与UNIX、Linux或多或少都有血缘关系(shell、bash等),但是在mac进行Linux开发,或者把macOS直接当作Linux来使用依然是说不过去的,这其中包括一些命令行的使用,一些基本的文件夹体系等(如,在Linux上的/home目录与在macOS下的/Users)不一致。如果想要在macOS上进行Linux的学习,或者进行Linux开发,最完美的方案自然是安装虚拟机。

众所周知,在Java中,存在着值比较与应用比较两种情况。例如,如下的比较,可以根据值比较与引用比较来跟容易的判断出结果来:

1
2
3
4
5
6
int a = 123;
int b = 123;
String s1 = new String("123");
String s2 = new String("123");
System.out.println(a == b); //true
System.out.println(s1 == s2); //false

这里,a与b由于是基本类型,所以Java在比较的时候直接就是按值来比较,而下面的s1与s2则是由于分别指向内容为“123”的字符串对象引用(关于string的细节,见本人的另一篇文章),而这两个字符串的地址并不一样,所以结果是false。

那么,今天要讨论的是,对于Java自动拆装箱的问题的深入探讨。如下所示,请问结果是什么呢?

1
2
3
Integer a = 666;
Integer b = 666;
System.out.println(a == b);

结果是false,您可能会说,这有什么好问的,Integer对象的比较,引用的比较,而这两个只是值相同,而对象不同的Integer对象罢了,所以当然为false。好,那么我再问你,下面的结果是什么?

1
2
3
Integer a = 100;
Integer b = 100;
System.out.println(a == b);

您可能说,哇,当我傻吗,当然还是false了。可是,结果是true。

为什么同样的情况下,当值变小了,结果就变为true了呢。

其实,Java中,对于可装箱的对象类型,都存在一个1字节的范围:-128到127。在这个范围类的数字,Java认为是常用的数字,所以自动进行了值比较,而不是进行引用的比较。所以,无论是Long还是Integer,只有你的值在-128到127,这两个对象的比较直接按照其所存储的值来进行。就像如下的情况:

1
2
3
4
5
6
7
8
9
10
11
12
Integer a = 128;
Integer b = 128;
Integer c = 127;
Integer d = 127;
Long e = -129L;
Long f = -129L;
Long g = -128L;
Long h = -128L;
System.out.println(a == b); //false
System.out.println(c == d); //true
System.out.println(e == f); //false
System.out.println(g == h); //true

关于String相关内容的学习,历来都是Java学习必不可少的一个经历。

以前一直想要好好总结一下String的相关的知识点,苦于没有时间,终于在今天有一个闲暇的时间来好好总结一下,也希望这文章能够加深我对于String相关内容的理解(ps:在我看来,学习某些知识点的时候把学到的想到的都记录下一方面能够加深自己学习印象,二者能够锻炼锻炼我的文笔