Java基础思维导图
2022-07-17 16:38:46 0 举报
AI智能生成
Java学习,从基础开始
作者其他创作
大纲/内容
Java8大基本类型
整数类型
byte:1字节 --默认值:0
对应包装类型:Byte --包装(引用)类型默认值:null,使用时需要判空
判空方式
普通:Byte !=null
jdk7: Objects.requireNonNull : Objects是final修饰的
jdk8:Optional.ofNullable : Optionnal是final修饰的<br>
可是回头一看:Optional类是申明为final的!!没法继承啊!<br><br>
因为像Optional类和LocalDateTime类都是值敏感的。jdk要求把值敏感的类设计成不可变类,否则对象就可以被变更。<br><br>题
申明为final<br>根据值来自定义equals()和hashCode()<br>绝对使用equals()方法而不是==进行比较<br>没有公开的构造器,而是提供工厂方法<br>
short: 2字节 --默认值:0
对应包装类型:Short --包装(引用)类型默认值:null,使用时需要判空
判空方式
java null 在前_java中判断对象为null时,null在前面还是后面<br>
<br>
int:4字节 --默认值:0
对应包装类型:Integer --包装(引用)类型默认值:null,使用时需要判空
判空方式
1、数据结构判空(map、list、set)<br>分为apache.lang3或者spring框架下:<br>
CollectionUtils.isEmpty() 为空<br><br>
CollectionUtils.isNotEmpty() 不为空<br>
2、对象判空:jdk7<br>
Objects.isNull() 为空<br><br>
Objects.nonNull() 不为空<br><br>
3、字符串判空<br>
StringUtils.isNotEmpty() 不为空<br>
4、isBlank()与isEmpty()的区别<br><br>String a = null;//没分配内存<br><br>String b = new String(); //分配了内存,内存指针无指向<br><br>String c = ""; //分配了内存,内存指针指向空字符串<br><br>String d= " "; //分配了内存,内存指针指向多个空格组成的字符串<br>
(1),public static boolean isEmpty(String str)<br>判断某字符串是否为空,为空的标准是str==null或str.length()==0<br>下面是示例:<br>StringUtils.isEmpty(null) = true<br>StringUtils.isEmpty(“”) = true<br>StringUtils.isEmpty(" “) = false //注意在StringUtils中空格作非空处理<br>StringUtils.isEmpty(” “) = false<br>StringUtils.isEmpty(“bob”) = false<br>StringUtils.isEmpty(” bob ") = false<br>
(2). public static boolean isBlank(String str)<br>判断某字符串是否为空或长度为0或由空白符(whitespace)构成<br>下面是示例:<br>StringUtils.isBlank(null) = true<br>StringUtils.isBlank(“”) = true<br>StringUtils.isBlank(" “) = true<br>StringUtils.isBlank(” “) = true<br>StringUtils.isBlank(”\t \n \f \r") = true //对于制表符、换行符、换页符和回车符StringUtils.isBlank()均识为空白符<br>StringUtils.isBlank(“\b”) = false //“\b"为单词边界符<br>StringUtils.isBlank(“bob”) = false<br>StringUtils.isBlank(” bob ") = false<br><br>
StringUtils.isEmpty() 为空<br>
StringUtils.isNotBlank() 不为空<br>
StringUtils.isBlank() 为空<br><br>
生成Integer对是有常量池的:在-128~127之间常量,就从缓存的IntegerCache类中获取
long:8字节 --默认值:0L
对应包装类型:Long --包装(引用)类型默认值:null,使用时需要判空
判空方式
浮点类型
float:4字节 --默认值:0f
对应包装类型:Float --包装(引用)类型默认值:null,使用时需要判空
判空方式
double:8字节 --默认值:0d
<span style="font-size: inherit;">对应包装类型:Double --包装(引用)类型默认值:null,使用时需要判空</span><br>
判空方式
引申知识
BigDecimal判空
很多人都知道,在进行金额表示、金额计算等场景,不能使用double、float等类型,而是要使用对精度支持的更好的BigDecimal。<br>
子主题
为什么阿里巴巴禁止使用BigDecimal的equals方法做等值比较?
equals()方法会比较值和精度(1.0与1.00返回结果为false),而compareTo()则会忽略精度,精度就是小数有几位<br>
错误案例
if ( bigdecimal = bigdecimal )<br>
因为BigDecimal是对象,所以不能用==来判断两个数字的值是否相等。<br>
if ( bigdecimal.equals( bigdecimal ) )<br>
比较值和精度,不适合比较
实际例子
<br> BigDecimal bigDecimal = new BigDecimal(1);<br> System.out.println("bigDecimal = " + bigDecimal);//bigDecimal = 1<br><br> BigDecimal bigDecimal1 = new BigDecimal(1);<br> System.out.println("bigDecimal1 = " + bigDecimal1);//bigDecimal1 = 1<br><br> System.out.println(bigDecimal.equals(bigDecimal1)); //true<br> // 整数类使用bigdecimal,精度一样<br><br> BigDecimal bigDecimal2 = new BigDecimal(1);<br> System.out.println("bigDecimal2 = " + bigDecimal2);//bigDecimal2 = 1<br><br> BigDecimal bigDecimal3 = new BigDecimal(1.0);//bigDecimal3 = 1<br> System.out.println("bigDecimal3 = " + bigDecimal3);<br> System.out.println(bigDecimal2.equals(bigDecimal3)); //true<br> // 浮点型在用bigdecimal 初始化是不精确的,但是返回一样<br><br> BigDecimal bigDecimal4 = new BigDecimal("1");<br> System.out.println("bigDecimal4 = " + bigDecimal4);//bigDecimal4 = 1<br><br> BigDecimal bigDecimal5 = new BigDecimal("1.0"); //bigDecimal5 = 1.0<br> System.out.println("bigDecimal5 = " + bigDecimal5);<br><br> System.out.println(bigDecimal4.equals(bigDecimal5));//flase
理解
BigDecimal(int)<br><br>BigDecimal(double) <br><br>BigDecimal(long) <br><br>BigDecimal(String)
最简单的就是BigDecimal(long) 和BigDecimal(int),因为是整数,所以标度就是0 :
public BigDecimal(int val) {<br><br> this.intCompact = val;<br><br> this.scale = 0;<br><br> this.intVal = null;<br><br>}<br><br><br><br>public BigDecimal(long val) {<br><br> this.intCompact = val;<br><br> this.intVal = (val == INFLATED) ? INFLATED_BIGINT : null;<br><br> this.scale = 0;<br><br>}
BigDecimal(double)
当我们使用new BigDecimal(0.1)创建一个BigDecimal 的时候,其实创建出来的值并不是正好等于0.1的,而是0.1000000000000000055511151231257827021181583404541015625 。这是因为doule自身表示的只是一个近似值。那么,无论我们使用new BigDecimal(0.1)还是new BigDecimal(0.10)定义,他的近似值都是0.1000000000000000055511151231257827021181583404541015625这个,那么他的标度就是这个数字的位数,即55。<br>其他的浮点数也同样的道理。对于new BigDecimal(1.0)这样的形式来说,因为他本质上也是个整数,所以他创建出来的数字的标度就是0。<br>所以,因为BigDecimal(1.0)和BigDecimal(1.00)的标度是一样的,所以在使用equals方法比较的时候,得到的结果就是true。<br>
BigDecimal(string)
当我们使用new BigDecimal("0.1")创建一个BigDecimal 的时候,其实创建出来的值正好就是等于0.1的。那么他的标度也就是1。<br>如果使用new BigDecimal("0.10000"),那么创建出来的数就是0.10000,标度也就是5。<br>所以,因为BigDecimal("1.0")和BigDecimal("1.00")的标度不一样,所以在使用equals方法比较的时候,得到的结果就是false。
布尔类型
boolean --默认值:false
对应包装类型:Boolean --包装(引用)类型默认值:null,使用时需要判空
判空方式
字符类型
char:2字节 --默认值:\u0000(null)<br>
对应包装类型:Charater --包装(引用)类型默认值:null,使用时需要判空
判空方式
一、空字符串与null区别<br><br>
1、类型
null表示的是一个对象的值,而并不是一个字符串。例如声明一个对象的引用,String a = null ;<br><br>""表示的是一个空字符串,也就是说它的长度为0。例如声明一个字符串String str = "" ;<br><br>
引申知识
在java中变量和引用变量是存在栈中(stack),而对象(new产生的)都是存放在堆中(heap):<br><br>
字符串对象与null的值不相等,且内存地址也不相等;<br><br>
public static void main(String[] args) {<br> String s1 = new String();<br> String s2 = null;<br> String s3 = "";<br> System.out.println("s1==s2 = " + s1==s2);//内存地址比较 false<br> System.out.println("s1 = " + s1.equals(s2));//值的比较 false<br> System.out.println("s2==s3 = " + s2==s3);//内存地址比较 false<br> System.out.println("s3.equals(s2) = " + s3.equals(s2));//值的比较 false<br> System.out.println("s1==s3" + s1==s3);//内存地址比较 false<br> System.out.println("s1.equals(s3) = " + s1.equals(s3));//值的比较 true<br> }
空字符串对象与null的值不相等,且内存地址也不相等;<br><br>
new String()创建一个字符串对象的默认值为"" (String类型成员变量的初始值为null)<br><br>
2、内存分配<br><br>
String str = null ; 表示声明一个字符串对象的引用,但指向为null,也就是说还没有指向任何的内存空间;<br><br>String str = ""; 表示声明一个字符串类型的引用,其值为""空字符串,这个str引用指向的是空字符串的内存空间;<br><br>
引申知识
“==”和equals 最大的区别是<br>
“==”是运算符,如果是基本数据类型,则比较存储的值;如果是引用数据类型,则比较所指向对象的地址值。<br>
equals是Object的方法,比较的是所指向的对象的地址值,一般情况下,重写之后比较的是对象的值。<br>
8大引用类型
统一extends Number 数字实现类<br>INumber 接口<br>
int intValue();<br><br> long longValue();<br><br> float floatValue();<br><br> double doubleValue();<br><br> default byte byteValue() {<br> return (byte)this.intValue();<br> }<br><br> default short shortValue() {<br> return (short)this.intValue();<br> }<br>
INumber下的方法只能是实例化之后的对象使用
所有包装类都重写了Object方法<br><br>
我们也很容易知道Object的方法有:<br>boolean equals(Object obj)<br>int hashcode()<br>String toString()<br>
equals 基本上用于判断当前对象和参数传入的对象是否相同,Object类的默认实现是比较地址。对于两个变量,指向同一个对象地址时,equals才会返回true,与==运算符结果相同。一般这个默认实现是不符合我们需要的比较两个对象相等,需要子类重写这个实现。以Long为例,其equals方法代码实现如下:<br>public boolean equals(Object obj){<br> if(obj instanceof Long){<br> return value==((Long)obj).longValue();<br> }<br> return false;<br>}<br>
对于Float,equals方法实现跟上面还有点区别,需要注意一下,其equals实现:<br>public boolean equals(Object obj){<br> return (obj instanceof Float) && (floatToIntBits((Float) obj).value) ==floatToIntBits(value));<br>}<br>上面代码出现了一个floatToIntBits()方法,这里将float的二进制表示看做int。为什么要使用这个方法呢?因为float类型要比较相等的时候,只有当他们表示的二进制完全一样的时候才相等。所以比较两个float相等转成成了二进制对应int值的比较。Double实现euqals方法也类似,有兴趣的可以自己找源码看看。<br><br>public boolean equals(Object obj) {<br> return (obj instanceof Double)<br> && (doubleToLongBits(((Double)obj).value) ==<br> doubleToLongBits(value));<br> }<br>
hashCode 返回一个对象的哈希值。哈希值是一个int类型的数,一般有对象中不变的属性值映射得来。一般在容器类会对对象进行区分。一个对象的哈希值不能改变,相同对象的哈希值相同,不同对象的可以相同,也可以不同,一般是不同。对于hashcode与equals的关系,我这里推荐一个博主的文章,写的比我详细,我这里就在这里引用他的文
阿里规范:只要重写equals就必须重写hashCode.
为什么呢?<br>因为set对象对比的是equals和hashCode,如果hashCode没有,<br>两个对象字面量一样,但是hashCode不一样,会将两个添加到set集合中
案例
在Set中为何要同时重写hashCode()和equals()呢?<br>不重写也可以,但是会丢失数据,比你认为的不重复数据,但是没有重写就添加不进去set集合
//以下为Object类<br>public boolean equals(Object obj) {<br> return (this == obj);<br>}<br><br>public native int hashCode();<br>
也就是说,hashCode()和equals()都是Object类中的方法。<br>在Object中,equals方法的本质就是 == ,即比较地址。<br>在没有重写的equals的类,equals比较的是地址。<br>而String、Date、File等类重写了equals方法,所以比较的是内容(字面量)。
2.2如何定义相等?<br>
Object类中equals方法认为的相等是,地址相等。<br><br>
@Test<br>public void testString() {<br> String s1 = new String("123");<br> String s2 ="123";<br> System.out.println(s1 == s2);//false<br> System.out.println(s1.equals(s2));//true<br>}<br>关于s1和s2,他们并不指向同一个实例对象,也就是说他们的地址并不相等。然而,在使用过程中,我们往往只关注String的内容,即字面量,故String类中重写了equals方法,也就是对equals来说,字面量相等,就认为他们相等。其实只是给何为相等重新下了个定义。何为相等,要根据业务场景去随时定义。默认的相等定义就是Object类中的equals方法,即比较地址。<br>当然,关于String类其实还要提到字符串常量池,常量池的对象地址是一样的 如果在 -128 -127之间取常量池,对象的地址一样<br>https://blog.csdn.net/weixin_43615816/article/details/123311738<br>
2.3Set中如何定义相等?<br>
其实,在Set中,如字符串,仍只需要比较字面量是否相等即可,对于其它对象,可由用户自定义相等规矩(重写equals方法)。<br>那为何还要同时重写hashCode()和equals(),即相等(equals)的对象必须具有相等的哈希码?<br><br>
@Test<br>public void testPerson() {<br> //Person 重写了equals方法,即比较id和name,没有重写hashcode<br> Person person1 = new Person(1001, "jack");<br> Person person2 = new Person(1001, "jack");<br> System.out.println(person1.hashCode());//1805013491<br> System.out.println(person2.hashCode());//951880373<br> System.out.println(person1.equals(person2));//true<br>}<br>
原因:当person1和person2这两个对象(equals)相等,即他们equals的结果为true,但他们各自的哈希码(很大概率)不相同(没有重写hashCode),当他们要存入同一个HashSet时,有可能就会因为哈希码不同导致计算得出的HashSet内部数组位置索引不一样,那么person1、person2很可能同时存入同一个HashSet中。
引申知识
如果自定义对象做为 Map 的键,那么必须重写 hashCode 和 equals;<br><br>
HashMap中的重写<br>
所有的key构成的集合是Set:无序的、不可重复的。<br>所以,key所在的类要重写:equals()和hashCode()。<br>所有的value构成的集合是Collection:无序的、可以重复的。<br>所以,value所在的类要重写:equals()。
很多时候我们常用的key是String类型,那么如果使用一般对象作为key值这个对象需要满足或者具备什么条件呢?<br>1.首先String底层重写了hashcode 和equals 方法,所以可以使用String对象作为key来使用。<br>2.如果自定义对象作为 map 的键,那么也必须重写 hashcode和equals。<br>3.只要重写equals,就必须重写hashcode。
引申知识:阿里规范
Object对象的colne尽量不使用,<br>因为是浅复制
Java API 的Comparable 接口如下:<br><br>
public interface Comparable<T> {<br> public int compareTo(T o)<br>}
Byte
静态方法直接调用:属于本身自己定义的方法<br>public static int compare(byte x, byte y) {<br> return x - y;<br> }
Integer、Long
静态方法直接使用 : 属于本身自己定义的方法<br>public static int compare(int x, int y) {<br> return (x < y) ? -1 : ((x == y) ? 0 : 1);<br> }<br><br><br>public static int compare(long x, long y) {<br> return (x < y) ? -1 : ((x == y) ? 0 : 1);<br> }<br>
该方法是实现Comparable接口的方法。实例对象才能使用,里边是使用的静态方法<br>public int compareTo(Long anotherLong) {<br> return compare(this.value, anotherLong.value);<br> }<br><br>public int compareTo(Long anotherLong) {<br> return compare(this.value, anotherLong.value);<br> }<br>
Folat
静态方法直接使用:<br>public static int compare(float f1, float f2) {<br> if (f1 < f2)<br> return -1; // Neither val is NaN, thisVal is smaller<br> if (f1 > f2)<br> return 1; // Neither val is NaN, thisVal is larger<br><br> // Cannot use floatToRawIntBits because of possibility of NaNs.<br> int thisBits = Float.floatToIntBits(f1);<br> int anotherBits = Float.floatToIntBits(f2);<br><br> return (thisBits == anotherBits ? 0 : // Values are equal<br> (thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)<br> 1)); // (0.0, -0.0) or (NaN, !NaN)<br> }
Double
静态方法直接使用:<br>如果double使用的值大小不一样,直接判断,如果一样,则需要转换成二进制<br>进行判断大小,因为double(双精度)和float(单精度)都是近似值,只有二进制<br>一样才一样呢。要使用精确不丢失精度,得使用bigdecimal<br><br>使用<和>对浮点数进行比较时,不够严谨,有这两个问题:0.0、-0.0的比较问题(0.0 > -0.0),以及NaN的问题(NaN永远比!NaN大),建议使用Double.compare()或Float.compare()进行比较。<br>源码中将浮点数转化为long类型的位序列,并根据IEEE754标准进行大小比较,可以解决这两个问题。<br><br><br>public static int compare(double d1, double d2) {<br> if (d1 < d2)<br> return -1; // Neither val is NaN, thisVal is smaller<br> if (d1 > d2)<br> return 1; // Neither val is NaN, thisVal is larger<br><br> // Cannot use doubleToRawLongBits because of possibility of NaNs.<br> long thisBits = Double.doubleToLongBits(d1);<br> long anotherBits = Double.doubleToLongBits(d2);<br><br> return (thisBits == anotherBits ? 0 : // Values are equal<br> (thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)<br> 1)); // (0.0, -0.0) or (NaN, !NaN)<br> }<br>
该方法是实现Comparable接口的方法。实例对象才可以使用<br>public int compareTo(Double anotherDouble) {<br> return Double.compare(value, anotherDouble.value);<br> }
引申知识
Java中double类型大小比较的五种方法<br><br>
在Java中 int类型数据的大小比较可以使用双等号, double类型则不能使用双等号来比较大小,如果使用的话得到的结果将永远是不相等,即使两者的精度是相同的也不可以。下面介绍几种比较double数据是否相等的方法,前三种可以比较正负数,后两种方法只能用于比较两数是否想等以及正数的大小。
1.使用BigDecimal<br><br>extends Number implements Comparable<BigDecimal><br>
Bigdecimal通过字符串构造出来的不会丢失精度,<br>但是使用double,float的浮点型数据构造出来的bigdecimal会丢失精度。<br>因为浮点型数据本来就不像整数型数据精确。
BigDecimal可以使用字符串和 double 类型创建对象,并且建议使用字符串创建,<br>因为在看起来数字相等的情况下,使用字符串的精度更高。
阿里规范:Decimal(小数的意思)<br>
BigDecimal的等值比较应使用CompareTo方法,而不是equals方法<br><br>说明:equals方法会比较值和精度(1.0与1.00返回结果为false).而compareTo则会忽略精度<br>
源码:<br>equals:<br>将此BigDecimal与指定的Object进行比较是否相等。与compareTo不同,此方法仅当两个BigDecimal对象的值和比例相等时才认为它们相等(因此,通过此方法进行比较时,2.0 不等于 2.00)。<br><br><br>compareTp:<br><br>将此BigDecimal与指定的BigDecimal进行比较。此方法认为两个值相等但比例不同(如 2.0 和 2.00)的BigDecimal对象是相等的。此方法优先于六个布尔比较运算符(<、==、>、>=、!=、<=)中的每一个的单独方法提供。执行这些比较的建议习惯用法是: (x.compareTo(y) < op > 0) ,其中 < op > 是六个比较运算符之一。<br>
禁止使用构造方法BigDecimal(double)的方式把double值转化为BigDecimal对象<br>
说明:Bigdecimal(double)存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常如:BigDecimal g = new BigDecimal(0.1F);实际的存储值为:0.10000000149正例:优先推荐入参为String的构造方法,或使用BigDecimal的valueOf方法,此方法内部其实执行了Double的toString,而Double的toString按double的实际能表达的精度对尾数进行截断。BigDecimal d1 = new BigDecimal("0.1");BigDecimal d2 = BigDecimal.valueOf(0.1)
2.使用包装类Double
compareTo是实现了compareble接口,<br>我觉的实现接口的普遍都是类要实例化<br>因为实现类的方法被@Override注解修饰<br>使用static修饰会报错<br>“Method does not override method from its superclass”<br>方法不会重写其超类中的方法<br><br><br>//2.使用包装类Double<br>Double dL = num1;<br>Double dR = num2;<br>if (dL.compareTo(dR) < 0)<br> System.out.println("num1 < num2");<br>else if (dL.compareTo(dR) == 0)<br> System.out.println("num1 == num2");<br>else<br> System.out.println("num1 > num2");<br><br><br>
3.在误差范围内运行相等<br>
4.转换成字符串<br>
可以将double数据转换成string然后借助string的compareTo方法来间接实现比较两个double数据是否相等。注意这种方法只适用于比较精度相同的数据,并且是只能用于比较正数的大小,负数比较结果异常,不过可以用于比较两数是否相等,此时正负数对结果没有影响。<br><br>
5.使用doubleToLongBits()方法<br>
使用sun提供的Double.doubleToLongBits()方法,该方法可以将double转换成long型数据,从而可以使double按照long的方法(<, >, ==)判断是否大小和是否相等,但是,这种办法还是只能用于比较正数,负数结果异常,比较两数相等与否是没有问题的。<br><br>
Java中“==”、“compareTo()”和“equals()”的区别
在比较两个对象或者数据大小的时候,经常会用到==、compareTo()和equals(),<br>尤其是在接入了Comparable接口后重写compareTo方法等场景,所以我们来理一下这三个的区别。<br><br>
1.等号——"==":<br>
等号是最简单也最容易理解的,如果等号的两边是基本数据类型,比如int,double,那么等号就用来单纯的比较他们的数值大小<br>如果等号两边放的是两个对象,那么就会比较他们在内存当中的地址。<br><br><br>
String a="abc";<br> String b="abc";<br> System.out.println(a==b);<br><br>答案是:true<br>因为相同的字符串内容,在地址上是一样。在Java中,String是有一个String pool的,里面存放了可以共享的字符串对象,在声明一个String对象后,会首先去找是否存在相同的String内容,如果有的话是不会创建新的对象的。在这里b实际上是引用了a的对象的值,他自己并没有创建对象,所以这里的答案是true。<br><br>但是如果我们接着<br>String c=new String(“abc”);<br>再<br>System.out.println(a==c);<br>那答案就是false,因为这二者的地址并不是一致的。<br>为什么呢?<br>因为这里是 new String 新创建对象。之前 “abc” 是编译器自动处理优化,因此可以去查找字符串池<br><br>
引申知识
String a="abc"与String b=new String("abc")的区别
1、常量池<br>指的是在编译期确定,并被保存在已编译的字节码文件中的一些数据,它包括类、方法、接口等中的常量,存放字符串常量和基本类型常量(public static final)。<br>2、栈(stack)<br><br>主要保存基本数据类型(或者叫内置类型)(char、byte、short、int、long、float、double、boolean)和对象的引用,数据可以共享,速度仅次于寄存器(register),快于堆。<br><br>3、堆(heap):用于存储对象<br>3、== :引用是否指向同一个对象<br>4、equals():比较里面的数值是否相等时<br>
<br>第1种:<br><br>String a="abc";<br>String b="abc";<br>System.out.print(a==b);<br><br>结果:true<br><br>原因:编译时,String a="abc" 会把"abc"放到常量池中,再定义b时,因为常量池中已存在“abc”,所有不会再创建,运行时JVM(JAVA虚拟机)则认为这两个变量赋的是同一个对象,所以返回true。<br><br>
第2种:<br><br>String a=new String("abc");<br>String b=new String("abc");<br>System.out.print(a==b);<br><br>结果:false<br><br>第二种中用构造器创建的对象是不会被放入常量池中,这句话是不对的。事实上,只要有引号的引用它就会在常量池中创建字符串,所以常量池中是存在abc的,只不过new的过程在堆中又创建了字符串abc。<br>
第3种<br><br>String a="abc";<br>String b=new String("abc");<br>System.out.print(a==b);<br><br>结果:false<br>原因:同上
第4种<br><br>String a="abcdef";<br>System.out.print(a=="abcdef");<br><br>结果:true<br><br>原因:运行出现的字符串常量,若是在常量池中出现过,则JVM会认为同一个对象,以节省内存开销,所以这两个字符串会被认为是同一个对象。
<br>第5种<br><br>String a="abcdef";<br>String b="";<br>String c=a+b;<br>System.out.print(c=="abcdef");<br><br>结果:false<br><br>原因:编译时,先将"abcedf"放在常量池中,而c的值则是在运行时在堆里创建的。所以为false。<br><br>
2.compareTo()
注意这里是String类型,其他同理
public int compareTo(String anotherString) {<br> int len1 = value.length;<br> int len2 = anotherString.value.length;<br> int lim = Math.min(len1, len2);<br> char v1[] = value;<br> char v2[] = anotherString.value;<br><br> int k = 0;<br> while (k < lim) {<br> char c1 = v1[k];<br> char c2 = v2[k];<br> if (c1 != c2) {<br> return c1 - c2;<br> }<br> k++;<br> }<br> return len1 - len2;<br> }<br>
可以观察出,这里实际上是获取的字符串(也可以是其他对象)的长度,然后作减法,这里的减法就是ASCII码的减法,所以compareTo()会返回数字,如果两个字符串内容相同,会返回0,字符串a大于字符串b,会返回相差的ASCII码的正数,字符串a小于字符串b,会返回相差的ASCII码的负数。<br><br>所以 System.out.println(a.compareTo(b))的答案是:0<br><br>
3.equals()
注意这里是String类型,其他同理
public boolean equals(Object anObject) {<br> if (this == anObject) {<br> return true;<br> }<br> if (anObject instanceof String) {<br> String anotherString = (String)anObject;<br> int n = value.length;<br> if (n == anotherString.value.length) {<br> char v1[] = value;<br> char v2[] = anotherString.value;<br> int i = 0;<br> while (n-- != 0) {<br> if (v1[i] != v2[i])<br> return false;<br> i++;<br> }<br> return true;<br> }<br> }<br> return false;<br>}<br>
可以观察出,equals是先用等号(==)直接来比较两个对象在内存当中的地址,如果相等会直接返回true,如果这两个对象的地址不一样,就会考虑这两个对象是不是String类型的,如果是String类型的,那先比较两个字符串长度是否一样,如果长度不一致,那100%不相等,直接返回false。长度一致则逐个比较<br><br>
4.compareTo()和equals的区别
compareTo()会返回二者的差值,即返回的是一个数字;而equals就简单一些,只返回true或者false。<br>最后,compareTo()和equals()都可以判断其他基本数据类型,比如说Integer,Java的源码中对这两者方法都做了一些重载,可以根据参数的类型去自动匹配相应的方法,他们的原理也非常简单,只是一些简单的减法或者(?:)这类判断。<br><br>
java.util.Date
public int compareTo(Date anotherDate) {<br> long thisTime = getMillisOf(this);<br> long anotherTime = getMillisOf(anotherDate);<br> return (thisTime<anotherTime ? -1 : (thisTime==anotherTime ? 0 : 1));<br> }
引申知识
new Date()返回的是系统的毫秒时间<br><br>public Date() {<br> this(System.currentTimeMillis());<br> }<br><br>this()调用的是本地的构造函数,<br>也就是下面这个函数,参数类型是 long
public static native long currentTimeMillis();<br>返回类型是long类型<br>System.currentTimeMillis()<br><br>自然就可以使用下面的构造函数了<br><br>public Date(long date) {<br> fastTime = date;<br> }<br>
分配一个Date对象并对其进行初始化,<br>以便它表示由字符串s指示的日期和时间,<br>这就像由parse方法解释一样。<br><br>已弃用<br>从 JDK 1.1 版开始,由DateFormat.parse(String s)取代。<br>参数:<br>s – 日期的字符串表示形式。<br>也可以看看:<br>DateFormat , parse(String)<br><br>@Deprecated<br> public Date(String s) {<br> this(parse(s));<br> }
引申知识
public abstract class DateFormat extends Format
SimpleDateFormat
public Date parse(String source) throws ParseException<br> {<br> ParsePosition pos = new ParsePosition(0);<br> Date result = parse(source, pos);<br> if (pos.index == 0)<br> throw new ParseException("Unparseable date: \"" + source + "\"" ,<br> pos.errorIndex);<br> return result;<br> }
编写 stringToDate<br>
yyyy-MM-dd HH:mm:ss大小写区别
<br>首先结论:yyyy-MM-dd HH:mm:ss是最标准的写法<br><br>下面展示不同出现的结果<br><br>月份如果小写的话 就是yyyy-mm-dd HH:mm:ss<br>这样子就会月份和分钟混了,两个都是小写mm,最后两个都显示分钟<br>MM是月份,mm是分钟<br>产生如下问题<br><br>2019-18-03 12:18:33 //18问题<br><br><br>小时如果小写的话 就是yyyy-MM-dd hh:mm:ss<br><br>这样子如果是下午两点半 大写的HH会表示为14:30 小写的hh会表示为2:30<br><br>2019-18-03 2:30:33<br>HH为24小时制,hh为12小时制<br><br>2019-18-03 14:30:33<br><br><br>
Java中强大的 接口 :Format<br>
Format的直接子类包括DateFormat、NumberFormat和MessageFormat。下面一一进行介绍<br><br>链接 : <br><br>https://www.jianshu.com/p/c8f16cab35e1<br>
接口 : DateFormat
子类:<br>SimpleDateFormat<br>
接口 :NumberFormat
子类:<br>DecimalFormat<br><br>
Java DecimalFormat四舍五入的坑及正确用法<br>
<br>一、DecimalFormat四舍五入的坑
1.1 有时候我们在处理小数保留几位小数时,想到了DecimalFormat这个类的使用,百度搜一把可能用到以下方式。<br><br>复制代码<br> 1 public static void main(String[] args) {<br> 2 String str="3.145";<br> 3 System.out.println(round1(str));<br> 4 }<br> 5 <br> 6 static String round1(String str){<br> 7 double a=Double.parseDouble(str);<br> 8 DecimalFormat df=new DecimalFormat("###.00");<br> 9 return df.format(a);<br>10 }<br>复制代码<br><br>1.2 初看好像没什么问题,四舍五入保留两位小数,最后输出3.15。当然精度要求不高,也无需计较。当涉及到精确统计时,这里的坑来了将上面的字符串改为“5”前面为奇数,如“3.155”,就瓜了,输出3.15。显然这里没满足要求,不是我们学校里的四舍五入。再上一段代码。<br><br>1 static String round2(String str){<br>2 double a=Double.parseDouble(str);<br>3 DecimalFormat df=new DecimalFormat("###.00");<br>4 df.setRoundingMode(RoundingMode.HALF_UP);<br>5 return df.format(a);<br>6 }<br><br><br>这里可以看到这个setRoundingMode()方法可以设定四舍五入的模式,原来四舍五入不光有我们学校里学的那种,还有其他模式。DecimalFormat默认情况下,它使用 RoundingMode.HALF_EVEN,此舍入模式也称为“银行家舍入法”,主要在美国使用。RoundingMode.HALF_UP这个模式才是我们学校里学的标准四舍五入模式。以上代码虽然舍了学校型模式仍然不准确,应该将double类型改为BigDecimal类型。<br>
二、学校型四舍五入几种正确使用
2.1 String直接格式化<br><br>1 static String round3(String str){<br>2 double d=Double.parseDouble(str);<br>3 return String.format("%.2f",d);<br>4 }<br><br> 2.2 BigDecimal结合DecimalFormat,BigDecimal比较好性能,数据处理量大不建议使用。<br><br>1 static String round4(String str){<br>2 BigDecimal bigDecimal=new BigDecimal(str);<br>3 DecimalFormat df=new DecimalFormat("###.00");<br>4 df.setRoundingMode(RoundingMode.HALF_UP);<br>5 return df.format(bigDecimal);<br>6 }<br><br> 2.3 BigDecimal单独使用,这个类也自带舍入模式设定方法。<br><br>1 static String round5(String str){<br>2 BigDecimal bigDecimal=new BigDecimal(str);<br>3 return String.valueOf(bigDecimal.setScale(2,RoundingMode.HALF_UP));<br>4 }<br>
接口 :MessageFormat
MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}.");<br>
String类中的format方法<br>
String result1 = String.format("小明今年%d岁,他住在%s,他的月工资有%.2f", 25,"北京市",6633.435);<br>System.out.println(result1);//输出:小明今年25岁,他住在北京市,他的月工资有6633.44<br>/*****************************************************/<br>double num = 123.4567899;<br>String result2 = String.format("%e", num);<br>System.out.println(result2);//输出:1.234568e+02
总结<br>1.Format中的子类都是不同步,所以需要注意线程安全问题<br>2.可能在某些地方我解释的还是不太清楚。学习最重要的是多去尝试,多编写代码测试,如果仅仅靠看就能学会的话,那你就看吧、
时间比较的时候,先获取毫毛值<br>在进行比较
8大引用类型转换
valueOf()方法进行转换成相应包装类型
引申知识
String.valueOf()
BigDecimal.valueOf()
应用场景:<br>1、BigInteger适合保存比较大的整型<br>2、BigDecimal适合保存精度更高的浮点型(小数)<br><br>
Decimal英文意思是小数<br>BigDecimal意思是大的小数
BigInteger
//当我们编程中,需要处理很大的整数,long不够用<br> //可以使用BigInteger的类来搞定<br> long l = 234459897895499999999999999999999l;//编译器报 “Long number too large”<br> System.out.println("l=" + l);<br><br><br>BigInteger bigInteger = new BigInteger("234459897895499999999999999999999");<br> System.out.println(bigInteger);<br> //1.在对BigInteger进行加减乘除的时候,需要使用对应的方法,不能直接进行 + - * /<br> BigInteger bigInteger2 = new BigInteger("100");<br> BigInteger add = bigInteger.add(bigInteger2);<br> System.out.println(add);//+<br><br> BigInteger subtract = bigInteger.subtract(bigInteger2);<br> System.out.println(subtract); //减<br><br> BigInteger divide = bigInteger.divide(bigInteger2);<br> System.out.println(divide);//除<br><br>
BigDecimal
//当我们需要保存一个精度很高的数时,double不够用<br> //可以用BigDecimal<br><br> //double d=19999.2323223423493423423432423;<br> //System.out.println(d);//输出 19999.2323223423 精度缺失<br><br> BigDecimal bigDecimal = new BigDecimal("19999.2323223423493423423432423");<br> BigDecimal bigDecimal2 = new BigDecimal("1.1");<br> System.out.println(bigDecimal);<br><br> //1.如果对BigDecimal进行运算,比如加减乘除,需要使用对应的方法<br> //2.创建一个需要操作的BigDecimal然后调用相应的方法即可<br> System.out.println(bigDecimal.add(bigDecimal2));//+<br> System.out.println(bigDecimal.subtract(bigDecimal2));//-<br> System.out.println(bigDecimal.multiply(bigDecimal2));//*<br> //在调用divide 方法时,指定精度即可.BigDecimal.ROUND_CEILING<br> //如果有无限循环小数,就会保留分子的精度 就是定义的bigDecimal 数对应的分子的精度,小数点后的位数<br> //不指定精度,可能就会抛出异常<br> System.out.println(bigDecimal.divide(bigDecimal2, BigDecimal.ROUND_CEILING));// / 可能抛出异常ArithmeticException<br><br>
parse+引用类型<br>
parseByte<br>
parseInt
parseLong
parseFloat
parseDouble
final可以修饰类、属性、方法和局部变量。
使用场景
当不希望类被继承时;
当不希望父类的某个方法被子类覆盖、重写时;
当不希望类的某个属性值被修改时;
当不希望某个局部变量被修改时。
注意事项和细节:<br>
子主题
1.final修饰的属性又叫常量,一般用大写字母和下划线命名;
2.final修饰的属性必须赋初始值,且一旦赋值不能被修改;(在定义时、构造器、代码块中都可以进行赋值)
3.如果final修饰的属性是静态的,则初始化的位置只能是定义时和静态代码块中,不能在构造器中赋值;
4.final类不能继承,但是可以实例化对象;
5.如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承。
6.一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法了。
7.final和static搭配使用,效率更高,底层编译器做了优化处理。
class Demo{
public static final int i = 16;
static{
system.out.println("我想hj了");
}
}
8.包装类(Integer,Double,Float,Boolean等都是final),String也是final类。
具体工作任务与完成情况
按时间
按项目
亮点与不足
工作亮点
工作不足
改进措施
个人方面
团队协作方面
下一阶段工作计划
收藏
0 条评论
下一页