目录
基本类型
Java中提供了基本类型有八种 分别是 byte short int long float double char boolean
基本类型的值可以直接储存在一个变量里,直接在变量上完成一些基本运算,例如相加、逻辑比较、位运算等。下面是一个Java程序的示例代码,展示了如何使用基本类型
public class BasicTypesExample {
public static void main(String[] args) {
byte b = 100; // 声明并初始化一个byte变量
short s = 200; // 声明并初始化一个short变量
int num = b + s; // 整型变量num表示b和s的和
System.out.println("b + s = " + num);
double d = 2.34; // 声明并初始化一个双精度浮点型变量
float f = 3.12f; // 声明并初始化一个单精度浮点型变量
double result = d * f; // 计算结果
System.out.println("d * f = " + result);
char ch = 'a'; // 声明并初始化一个字符型变量
boolean flag = true;// 声明并初始化一个布尔型变量
System.out.println("字符 " + ch + " 是否是小写字母?" + Character.isLowerCase(ch)); // 使用Character类中的isLowerCase()方法判断ch是否是小写字母
System.out.println("flag 的反码是 " + !flag); // 取反运算符
}
}
引用数据类型
引用类型可以是用户自定义类型 也可以是Java各种包中封装的类型 并且 数组 对象 都是引用类型 所有引用类型的默认值都为null
引用类型与基本类型不同 引用类型变量保存的是对象的地址,因此对于引用类型变量的比较,需要使用equals()方法或者“==”运算符。
基本类型之间的比较
在基本类型之间我们可以使用使用“==”来进行比较
public static void main (String[] args) {
int a = 10;
int b = 10;
double c = 10.0;
double d = 10.0;
System.out.println("a == b :" + (a == b));
System.out.println("c == d :" + (c == d));
}
但是在引用类型中 如果我们想比较两个引用类型的值是否相等 我们就需要借助到equals来比较
public static void main (String[] args) {
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1.equals(s2));
}
并且如果我们使用等号的话 我们输出结果会是false 因为我们在介绍引用类型就已经提到了 我们的引用类型存储的是地址 两个不同的引用去比较是否相等比较的是他们的地址是否相同 当然是不一样的啦 但是还是会存在特殊情况的 我们来看如下的代码
public static void main (String[] args) {
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2);
}
到了此时 我们的s1 跟 s2比较此处会输出true 这是为何 保存的不是地址嘛 怎么会变的 一样 此时我们可以回顾一下当初讨论的String的不可变性 其中提到了常量池的概念 我们可以借助我们的常量池来解释这个问题 因为我们的“hello”字符串在创建的 时候 会在字符串常量池中也创建出一个hello 在我们对于他引用的时候 我们就会在常量池中查找这个字符串是否存在 如果这个字符串已经存在的话 我们的引用类型的变量就可以直接指向这个常量池中的元素 上述的代码就是因为同时指向了常量池中的hello 所以会出现输出结果为true的结果
那么我们又要提出新的问题 如果我们将s2换成创建一个新的对象呢?
public static void main (String[] args) {
String s1 = "hello";
String s2 = new String("hello");
System.out.println(s1 == s2);
}
此时我们的输出变为了false 这是为啥嘞 这还是回到我们线程池的解释 我们的s2的确创建了一个新的对象 并且这个对象指向的hello也是常量池中对象 我们可是要记得 如果对于引用类型进行比较 我们比较的是地址哦 虽然s2指向的对象是指向hello的 但是其中还间隔有一共对象哦 那么我们如何验证其中的值是否相等呢 我们还是要用到我们的equals
public static void main (String[] args) {
String s1 = "hello";
String s2 = new String("hello");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
}
如果对于字符串常量池不明确 此处是我们的 String的不可变的博客 其中有这明确的解释
与大佬展开讨论String的不可变性https://guobinglin.blog.csdn.net/article/details/128355409?spm=1001.2014.3001.5502对了 我们的自定义类型是不能使用我们的equals方法的 所以说我们要在我们的自定义类中重写我们的equals方法哦
基于Comparable的比较
除了使用equals()方法和“==”运算符比较引用类型变量,Java还提供了一个基于接口的比较方式,即使用Comparable接口。该接口定义了一个比较方法compareTo(),用于比较两个对象之间的大小关系。实现Comparable接口需要重写compareTo()方法。该方法需要返回一个整数值,表示当前对象与参数对象的大小关系。如果当前对象比参数对象小,则返回负整数;如果当前对象与参数对象相等,则返回0;如果当前对象比参数对象大,则返回正整数。
我们来以下的代码演示一下 我们的每个类代表一个学生 如果我们想要对于两个学生类之间做比较 要做一个排序的话 我们就需要借助到我们的Comparable接口实现compareTo方法
class Student implements Comparable<Student>{
int id;
int age;
String name;
public Student(int id,int age,String name){
this.id = id;
this.age = age;
this.name = name;
}
@Override
public int compareTo (Student o) {
return this.age - o.age;
}
}
public class Demo5 {
public static void main (String[] args) {
Student zhangSan = new Student(1,14,"zhangsan");
Student liSi = new Student(2,8,"lisi");
System.out.println(zhangSan.compareTo(liSi));
}
}
以上是解决掉了我们的引用类型之间比较其中值的问题 但是也带来了另一个大问题 就是说 我们如果直接在Student类中实现我们的Comparable接口的话 一旦重写compareTo方法 那么我们对于这个类比较的时候就只能使用我们定死的比较规则 这显然是不符合我们代码的“高内聚 低耦合”的 所以说 为了解决这个问题 我们衍生出一个比较器
class Student implements Comparable<Student>{
int id;
int age;
String name;
public Student(int id,int age,String name){
this.id = id;
this.age = age;
this.name = name;
}
@Override
public int compareTo (Student o) {
return this.age - o.age;
}
}
class StudentComparable implements Comparator<Student> {
@Override
public int compare (Student o1 , Student o2) {
return o1.age - o2.age;
}
}
public class Demo5 {
public static void main (String[] args) {
Student zhangSan = new Student(1,14,"zhangsan");
Student liSi = new Student(2,8,"lisi");
StudentComparable studentComparable = new StudentComparable();
System.out.println(studentComparable.compare(zhangSan,liSi));
//System.out.println(zhangSan.compareTo(liSi));
}
}
此处我们使用了一个类实现了我们的Comparator接口 并且重写了我们的compare方法 这样做的好处是什么呢 这个比较器就可以基于我们要按照从小到大 或者从大到小排序来说 实现我们的比较器 在使用Collection.sort()中就可以传入我们的这个比较器 也可以在其他地方使用我们类之间的比较 实现我们多种比较形式
总结
Object,equals :因为Object类是所有类的父类 所以都可以直接调用equals来进行比较其中的值 不过只能比较是否相等 也就是说 返回来类型是boolean类型
Comparable.compareTo: 需要在类中实现该接口并且重写该方法 但是这么做的话对于代码的侵入性太强 在原则上不满足我们代码的“高内聚 低耦合”
Comparator.compare:需要实现一个比较器对象 使用起来非常灵活对于代码的侵入性很弱