基本数据类型 & switch & 数组 & 变量 & final & static & 面向对象 & 包装类 & 字符串 & 正则表达式 & Object & 日期

Java思维导图

一、基本数据类型
1、整型
  • byte:1字节(-2 的 7 次方到 2 的 7 次方-1)
  • short:2字节(-2 的 15 次方到 2 的 15 次方-1)
    +=、-=、*=、/=、%=自带强转功能
  • int:4字节(-2 的 31 次方到 2 的 31 次方-1)
    • 整数直接量默认为int型,超范围则编译错误(-21个多亿到21个多亿)
    • 整数相除,小数位无条件舍弃
    • 整数运算时超出范围,则发生溢出,溢出需要避免
  • long:8字节(-2 的 63 次方到 2 的 63 次方-1)
    • 长整型直接量需在数字后加L或l
    • 运算时若有可能溢出,建议在第1个数字后加L
    • System.currentTimeMillis()用于获取自1970.1.1零时到此时此刻的毫秒数
2、浮点型
  • float:4字节
    • float需在数字后加f或F
  • double:8字节
    • 浮点型直接量默认为double型
    • double和float型数据运算时,有可能会出现舍入误差,所以精确运算场合不能用,精确运算建议用BigDecimal
3、逻辑型
  • boolean:1字节
    • 默认为false
4、字符型
  • char:2字节
    • 采用Unicode字符集编码
    • 表现形式是char,实际存储是int(0-65535)
    • ASCII码: ‘a’-97 ‘A’-65 ‘0’-48
    • 字符直接量必须放在单引号中,只能有一个
    • 特殊符号需要 \ 转义
二、switch(expr)
  • 早期的JDK,expr可以是byte、short、char、int
  • JDK1.5后,expr可以是enum
  • JDK1.7后,expr可以是String,不可以是long
三、数组
  • 数组
    • 是一种数据类型(引用类型),也是一种对象
    • 数组大小不能任意改变
    • 不属于原生类 (原生类是一种基本数据类型)
  • 初始化
    • int[] arr = new int[4];
    • int[] arr = {1,2,3,4};
    • int[] arr = new int[]{1,2,3,4};
    • int[] arr; arr = {1,2,3,4}; //编译错误,此方式只能声明的同时初始化
    • arr = new int[]{1,2,3,4}; //正确
  • 复制
    • System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
      灵活性好,效率高
    • Arrays.copyOf(arr, length); // 数组的扩容
      灵活性差,效率低,但是可以扩容
  • Arrays.sort(arr); 排序
四、变量

由字母、数字、_、$组成,不能以数字开头

  • 成员变量
    • 实例变量
      • 无static修饰,有默认值
      • 属于对象的,存储在堆中,通过对象点来访问,对象被回收时一并被回收
    • 静态变量
      • 由static修饰
      • 属于类的,存储在方法区中,通过类名点来访问
  • 局部变量
    • 调用方法时存储在栈中,方法结束栈帧被清除时一并被清除
    • 可以与成员变量同名,使用时采取就近原则
五、final(最终不可改变)

JDK中的一些基础类库被定义为final,如String、Math、Integer、Double等等。

  • 修饰变量:变量不能被改变
    • 编译期常量
      类加载时完成初始化,编译后带入到任何计算式中,只能是基本类型
    • 运行期常量
      基本数据类型或引用数据类型,引用不可变,但引用的对象内容可变
    • 成员变量与局部变量区别
      修饰成员变量,可以在声明的同时初始化,或在构造方法中初始化
      修饰局部变量,只要在用之前初始化即可
  • 修饰方法:方法不能被重写
  • 修饰类:类不能被继承
  • 好处
    • 提高性能
      jvm和Java应用都会缓存final变量
    • 可共享
      可以在安全的多线程环境下进行共享,不需要额外的同步开销
    • jvm会对方法、变量和类进行优化
  • final static(常量)
    • 必须声明同时初始化
    • 通过类名点来访问,常量不能被改变
    • 编译器在编译时将常量自动替换为具体的值
    • 何时用:数据经常使用且永远不变
六、static(静态)
  • 静态变量
    • 属于类的,存储在方法区中,只有一份
    • 常常通过类名点来访问(不建议通过对象名访问)
  • 静态方法
    • 属于类的,存储在方法区中,只有一份
    • 静态方法不能直接访问实例成员,需要用对象点来访问
      静态方法没有隐式的this传递,就没有对象
    • static方法不能被abstract修饰,不能被覆盖,因为static是编译时静态绑定的,而方法重写是运行时动态绑定的。
  • 静态块
    • 属于类的,在类被加载期间自动执行,只执行一次
  • 执行顺序
    父类静态代码块 --> 子类静态代码块 --> 父类非静态代码块 --> 父类构造方法 --> 子类非静态代码块 --> 子类构造方法
七、访问控制修饰符

类的访问修饰符只能是public或默认的​

任何类 父子类 同包类 本类
public
protected
default
private
八、面向对象
  • 封装
    • 类: 封装对象的属性和行为
    • 方法: 封装业务逻辑功能
    • 访问控制修饰符: 封装具体的访问权限
  • 继承
    • 作用:代码复用
    • 特点:单继承,传递性,多接口实现
    • 优点
      • 子类能自动继承父类的接口
      • 创建子类对象时,无须创建父类的对象
    • 缺点
      • 子类与父类具有耦合,子类依赖于父类的实现
      • 增加系统结构复杂度
      • 不支持动态继承(在运行时,子类无法选择不同的父类)
      • 子类不能改变父类的接口
  • 多态
    • 行为多态(所有抽象方法)、对象多态(所有对象)
    • 向上造型、强制类型转换(想访问派生类所特有的)、instanceof判断
    • 多态的表现形式
      • 重写:根据对象的不同来多态
      • 重载:根据参数的不同来多态
九、包装类
1、存在意义

Java是一个面向对象编程的语言,而基本类型不具有对象的性质,引入包装类可以使基本类型具有对象的性质。比如在使用Collection集合类型时一定要使用包装类型,使其具有对象的性质,且为其添加了属性和方法,方便操作。

  • 可以参与面向对象编程
  • 解决不能参与面向对象编程 (多态)
2、特点
  • 包装类被final修饰,不可变类,一旦构造对象就不可改变
  • 六种包装类继承Number,Number是抽象类(八种基本数据类型中的包装类,除Character和Boolean继承于Object类)
  • 这六种包装的数据可以相互转换 (在Number中有相互转换的方法)
3、自动拆装箱

自动拆装箱特性始于JDK1.5版本,编译器会自动添加代码

  • 自动装箱(基本数据类型–>包装类型)
    • 给直接量的范围在-128~127,会有对象重用,如果不在这个范围会创建对象
    • 缓冲的值一旦超过范围就会强制new对象
    • Integer i = 100; // 编译器会改为new Integer(100); 底层调用Integer.valueOf(100)方法实现;
  • 自动拆箱(包装类型–>基本数据类型)
    • int i = new Integer(6); // 底层调用i.intValue();方法实现
4、总结==
  • 两个通过new生成的Integer变量永远是不相等的
    Integer i = new Integer(100); 
    Integer j = new Integer(100); 
    System.out.print(i == j); //false
    
  • Integer变量和int变量比较时,只要两个变量的值是相等的,则结果为true(因为包装类Integer和基本数据类型int比较时,java会自动拆包装为int,然后进行比较,实际上就变为两个int变量的比较)
    Integer i = new Integer(100); 
    int j = 100;
    System.out.print(i == j); //true
    
  • 非new生成的Integer变量和new Integer()生成的变量比较时,结果为false(因为非new生成的Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,两者在内存中的地址不同)
    Integer i = new Integer(100); 
    Integer j = 100;
    System.out.print(i == j); //false
    
  • 对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true
    Integer i = 100;
    Integer j = 100;
    System.out.print(i == j); //true
    
  • 对于两个非new生成的Integer对象,进行比较时,如果两个变量的值不在此区间,则比较结果为false
    Integer i = 128;
    Integer j = 128;
    System.out.print(i == j); //false
    
    java在编译Integer i = 100 ;时,会翻译成为Integer i = Integer.valueOf(100);
    public static Integer valueOf(int i){
    	assert IntegerCache.high >= 127;
     	if (i >= IntegerCache.low && i <= IntegerCache.high){
        	return IntegerCache.cache[i + (-IntegerCache.low)];
     	}
     	return new Integer(i);
    }
    
5、Int和integer的区别
  • 类型不一样
    int是java的8种基本数据类型之一。
    Integer是Java为int类型提供的包装类。
  • 默认值不一样
    int变量的默认值为0。
    Integer变量的默认值为null。(Integer可以区分出未赋值和值为0的区别)
    比如:学生A没来参加考试,学生B参加考试但是都答错了,则学生A的成绩是null,学生B的成绩是0分。
十、字符串
1、String介绍
  • java.lang.String被final修饰,不能被继承
  • 字符串一旦创建,对象永远无法改变,但字符串引用可以重新赋值
  • Java字符串在内存中采用Unicode编码,一个字符对应两个字节的定长编码
  • 频繁修改字符串就不要使用String
2、String相关方法
  • length() 获取长度
  • indexOf 检索
    • int indexOf(String str): 返回第一次str出现的位置,找不到返回-1
    • int indexOf(String str, int fromIndex): 从字符串的fromIndex位置开始检索
    • int lastIndexOf(String str, int fromIndex): 返回最后一个出现的位置
  • substring 获取子串
    • String substring(int beginIndex): 从下标beginIndex开始到字符串结尾的子字符串
    • String substring(int beginIndex, int endIndex): 包头不包尾
  • toUpperCase、toUpperCase 大小写转换
  • valueOf 将其他类型转换为字符串类型
  • split 以给定字符进行截取
  • format 字符串格式
    • str=“123+456”; String[]s = str.split("\+");
  • trim去掉两端的空字符
  • charAt 返回字符串指定位置的字符
  • startsWith、endsWith 检测字符串是否以指定字符串开头、结尾
3、String&StringBuffer&StringBuilder
String StringBuffer StringBuilder
相同点 都是final类,不允许继承
区别 长度不可变 长度可变
-- 线程安全、同步处理、性能稍慢 非线程安全、并发处理、性能更好
4、String
  • 因为String不能被继承,通常使用StringUtils、ObjectUtils来增强String的功能。
  • String内部重写了hashCode和equals。
  • substring
    会创建新字符串; 新字符串是在运行时在堆里创建的。
  • String str = “ABC”;
    可能创建一个对象或者不创建对象。
    如果“ABC”在String常量池里不存在,则会创建一个String对象“ABC”,然后str指向这个内存地址;
    如果存在,则不创建对象,指向已存在内存地址,之后都是String的拷贝,Java中称为“字符串驻留”,所有字符串常量都会在编译之后自动驻留。
  • String str = new String(“ABC”)
    至少创建一个对象,也可能两个。
    因为new,肯定会在堆中创建一个str对象,它的value值是“ABC”,如果这个“ABC”在字符串常量池里不存在,会创建“ABC”对象。
    String s1= “a”; String s2 = “a”; 此时 s1 == s2 返回 true
    String s1= new String(“a”); String s2 = new String(“a”); 此时 s1 == s2 返回 false
  • final
    final会在编译器被优化,且被直接运算好。
    • String为什么被final修饰?
      如果String不是final,那么子类就可以继承String类,然后子类可以重写其方法,这些重写的方法可以修改字符串,就违背了String的不可变性。
    • 不可变原因
      • 安全
        字符串常常用来表示url,文件路径,如果可变,会存在安全隐患。
      • 提高效率
        比如String str1 = “abc”; “abc”放到常量池里。String str2 = “abc”; str2的“abc”不会复制,只会多个引用指向原来的常量,这样就提高了效率。前提是String不可变,如果可变,多个引用指向同一个字符串,那么一个引用改变字符串,则其他引用也被影响。
      • String不可变,hashCode就一样,不用每次重新计算

例子

/**
 * final在编译器被优化,且会被直接运算好
 */
public class TestAwen {
	public static final String a1 = "a";
	public static String a2 = "a";
	
	public static void main(String[] args) {
		String a = "a";
		final String b = "b";  
		final String c = a + b;
		String d = a + b; 
		String e = a + "b";
		String f = "a" + b;
		String g = "a" + "b";
		String h = "ab";
		String i = new String(h);
		String j = a1 + b;
		String k = a2 + b;
		
		System.out.println(c == h);  // false
		System.out.println(d == h);  // false
		System.out.println(e == h);  // false
		// f、g、h在编译时优化,运算为字符串常量ab
		System.out.println(f == h);  // true
		System.out.println(g == h);  // true
		System.out.println(i == h);  // false
		System.out.println(j == h);  // true
		System.out.println(k == h);  // false
	}
}
  • 用“+”来拼接字符串时,底层会通过StringBuilder实例的append()方法来实现。
  • String intern(); 重用String对象
    • JDK1.7之前,字符串常量池放入方法区;
    • 自从JDK1.7开始,字符串常量池放入堆中;
    • 当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 确定),则返回池中的字符串。否则,常量池中直接存储堆中该字符串的引用(1.7 之前是常量池中再保存一份该字符串)。
    • 源码:public native String intern();
    • 例1
      String s = new String("1");  // 常量池中生成“1”,堆中创建字符串对象
      s.intern();  // s对象去常量池中找,发现“1”已经存在与常量池中
      String s2 = "1";  // s2指向常量池中的“1”
      System.out.println(s == s2);// false  // s指向堆中的字符串对象,s2指向常量池中的“1”,两者引用地址明显不同
      String s3 = new String("1") + new String("1");  // 常量池中生成“1”;堆中生成s3引用指向的对象(内容为“11”),但是此时常量池中没有“11”
      s3.intern();  // 将s3中的“11”放入常量池中,此时常量池中不存在“11”字符串,JDK1.6是直接在常量池中生成一个“11”对象;JDK1.7直接存储堆中的引用
      String s4 = "11";  // 去常量池中找,发现已经存在,则指向s3引用的对象 
      System.out.println(s3 == s4);// true
      
    • 例2
      String s3 = new String("1") + new String("1");  // 常量池中生成“1”;堆中生成s3引用指向的对象(内容为“11”),但是此时常量池中没有“11”
      String s4 = "11";  // 去常量池中找“11”,发现没有则生成“11”
      s3.intern();  // 去常量池中找“11”,发现已经有了
      System.out.println(s3 == s4);// false
      
    • 例3
      String str1 = new String("SEU") + new String("Calvin"); 
      System.out.println(str1.intern() == str1);// true   // str1.intern()发现常量池中不存在“SEUCalvin”,因此指向了 str1
      System.out.println(str1 == "SEUCalvin");// true  // "SEUCalvin"在常量池中创建时,也就直接指向了 str1 了
      
    • 例4
      String str2 = "SEUCalvin";//新加的一行代码,其余不变
      String str1 = new String("SEU") + new String("Calvin");
      System.out.println(str1.intern() == str1);// false  // str2 先在常量池中创建了“SEUCalvin”,然后str1.intern()就直接指向了 str2
      System.out.println(str1 == "SEUCalvin");// false  // 所以谁都不搭理在堆空间中的 str1 了
      
  • hashCode和equals
    • 当equals被重写时,必须重写hashCode方法,以维护hashCode方法的常规规定(规定声明两个相同的对象必须有相同的hashCode);
      • 当equals为true时,hashCode为true;
      • 当hashCode为false时,equals为false;
      • 当hashCode为true时,equals不一定为true;
    • 如果重写equals而不重写hashCode
      • 比如存储散列集合时(Set),如果只重写了equals,没有重写hashCode,则在集合中将会存储两个值相同的对象,从而导致混淆。
  • 追加、插入、替换的方法返回结果是this,toString方法返回的是String
  • 有没有哪种情况用+做字符串连接比调用StringBuffer / StringBuilder对象的append方法性能更好?
    如果连接后得到的字符串在静态存储区中是早已存在的,那么用+做字符串连接是优于StringBuffer / StringBuilder的append方法的。
  • 字符串的==与equals
String s1 = "HelloWorld";
String s2 = new String("HelloWorld");
String s3 = "Hello"+"World";
System.out.println(s1==s2);  // false
System.out.println(s1==s3);  // true
System.out.println(s1.equals(s2));   // true
System.out.println(s1.equals(s3));  // true
System.out.println(s1.intern()==s2.intern());   // true
​​
StringBuffer s1 = new StringBuffer("a"); 
StringBuffer s2 = new StringBuffer("a"); ​​
​s1.equals(s2) //是false   // 因为StringBuffer类中没有重新定义equals这个方法,因此这个方法就来自Object类
5、StringBuffer & StringBuilder
  • StringBuffer 和 StringBuilder中所有方法都相同。
  • StringBuffer 在 StringBuilder的方法上添加了synchronized,保证线程安全。
    • StringBuffer:线程安全、同步处理、性能稍慢
    • StringBuilder:非线程安全、并发处理、性能更好
  • 注意:StringBuffer和StringBuilder内部没有重新定义equals方法,因此用equals比较值是否相等时,结果为false
十一、正则表达式
  1. 正则表达式
    是一组特殊的字符,描述一个字符串格式
    对字符串可以进行复杂操作
    不关心内容是否有效,只关心格式是否正确
  2. 作用: 匹配字符串是否满足给定格式
  3. 字符集合
    [ ] 表示一个字符
    [123] 表示123中任意一个字符
    [0-9] 表示0~9中任意一个字符
    [ ^123 ] 除了123的任意字符
    [a-z&&[ ^b ]] a~z中除了bc以外的任意一个字符
  4. 数量词
    x? 表示0个或1个x
    x* 表示0个或任意多个x
    x+ 表示1个到任意多个x
    x{n} 表示n个x
    x{n, } 表示n个到任意多个x
    x{n, m} 表示n个到m个x
  5. 预定义
    . 任意一个字符
    \d 任意一个数字字符,相当于[0-9]
    \w 单词字符,相当于[a-zA-Z0-9_]
    \s 空白字符
    \D 非数字字符
    \W 非单词字符
    \S 非空白字符
  6. 分组( ): 将一系列正则表达式看作整体,分组与分组直接可以用"|"表示或
  7. “^“和”$” 表示字符串开始和结束,不写方法内部自动添加
  8. 方法
    boolean matches(String regex) 将一个字符串与正则表达式进行匹配
    String[] split(String regex) 将字符串拆分成字符串数组
    String replaceAll(String regex, String replacement) 将字符串中匹配正则表达式regex的字符串替换成replacement
  9. 常用正则
  • Email地址:^\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*$
  • 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
  • 手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
  • 身份证号(15位、18位数字):^\d{15}|\d{18}$
  • 短身份证号码(数字、字母x结尾):^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$
  • 帐号是否合法(字母开头,允许8-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{7,15}$
十二、Object
1. 所有类的超类

直接继承: 创建class后没有继承任何类,在Java编译器编译的时候,自动添加关键字extends,继承Object类
间接继承: 这个类继承了另一个类,类外的类间接或直接继承Object

2. String toString()

没有重写输出的是地址值 (当前类继承Object类,Object类中输出的是当前对象的地址值)
重写后输出的给定的内容

3. boolean equals()

equals没有重写比较地址值,重写后比较内容、= =是比较值是否相等
String是final类,已经重写了toString方法
= =比较是否是一个对象 (可能值相等,但不是一个对象)
equals比较值是否相等

十三、日期操作
1. Date

java.util.Date

Date的每一个实例用来表示一个确切的时间点; 内部(对象)维护了一个long值,距1970.1.1的毫秒值;
正数是1970年以后的日期,负数是1970年以前的日期;
由于Date设计上存在缺陷(时区、千年虫),导致大部分方法设置为“过时的”(不建议使用)。

toString()

格式: Sat Sep 08 16:13:35 CST 2018;
Date重写了toString,返回的字符串显示的是当前Date表示的时间;

long getTime()

获取Date内部维护的long值

void setTime(long)

设置一个long值,使Date表示该long值所表示的时间

大部分方法已过时(eg: getYear()、getMonth()等)

2. SimpleDateFormat

java.text.SimpleDateFormat

根据给定日期格式将String与Date相互转换: Date–>String 格式化、​String–>Date​ 解析

日期格式

y-年、M-月、d-日 写M,如果表示两位数的月份,最后还是会自动显示两位月份
E-星期、a-AM或PM标识
H-小时(24)、h-小时(12)、m-分钟、s-秒

构造方法

SimpleDateFormat()
SimpleDateFormat(String pattern)
用给定模式和默认语言环境的日期格式符号构造

String format(Date date) Date–>String

将给定的Date,转换为SimpleDateFormat指定日期格式的字符串

Date parse(String source) String–>Date

将给定的字符串按照SimpleDateFormat指定日期格式解析为Date对象;
注: 如果字符串格式和SimpleDateFormat格式不一致,在解析时会发生异常: ​java.text.ParseException: Unparseable date

3. Calendar
  • java.util.Calendar 抽象类,常用实现类是格里高里历(阳历)。
  • getInstance() 使用Calendar静态方法创建实例。
  • Date getTime() Calendar–>Date
  • void setTime(Date date) Date–>Calendar
  • void set(int field, int value) 针对不同时间分量单独设置值
    • 设定月: 月从0开始,0表示1月,或者可以使用具体月的常量
    • 设定日: DATE月中天、DAT_OF_MONTH与DATE一致
  • int get(int field) 获取对应时间分量的值
    • 获取月: 需要加1,因为月是从0开始
    • 获取时: HOUR是12小时制、HOUR_OF_DAY是24小时制
    • 获取星期: 国外是从星期日开始,从1开始
  • int getActualMaximum(int field) 获取某一时间分量所允许的最大值
  • void add(int field, int value) 对指定时间分量加上给定的值
    若给定的值是负数,则是减去给定的值
  • 日期开发思路
    • Step1.获取用户输入的日期字符串
    • Step2.使用SimpleDateFormat将其转换为Date
    • Step3.创建一个Calendar,使其表示Date表示的日期
    • Step4.使用Calendar根据需求计算时间
    • Step5.将Calendar转换为一个Date
    • Step6.使用SimpleDateFormat将Date转换为字符串后显示给用户

猜你喜欢

转载自blog.csdn.net/awen6666/article/details/103246288