Java发展
- 1991年4月,James Gosling博士领导启动绿色计划,开发出Oak语言;
- 1995年5月23日,Oak语言改名为Java,发布Java1.0版,第一次提出"write once, run anywhere"口号;
- 2006年12月11日,Sun公司用Java SE,Java EE和Java ME分别替代J2SE,J2EE和J2ME;
- 2009年4月20日,Oracle公司正式收购Sun公司;
Java环境变量配置相关
- Path/PATH环境变量:变量值是一系列路径,Win系统依次在路径中查找命令,找到则该命令可执行;
- 使用JDK1.5之前的版本,才需要设置CLASSPATH环境变量;
- Win操作系统不区分大小写,故设置Path与PATH无区别;
Java基本数据类型
Java是强类型语言,强类型包含两方面含义:
- 所有变量必须先声明,后使用;
- 指定类型的变量只能接受符合其类型的值;
Java中共有8种基本类型(primitive type),分别有对应的包装类(wrapper class);
基本类型存储在栈中,因此存取速度要快于在堆中的包装类对象;
Java基本类型中不存在无符号类型,字段长度和取值范围固定,基本类型的取值范围以 常量形式定义在对应的包装类中(Boolean除外),
基本类型 | 字节位数 | 对应包装类 |
boolean | 1 | Boolean |
char | 2 | Character |
byte | 1 | Byte |
short | 2 | Short |
int | 4 | Integer |
long | 8 | Long |
float | 4 | Float |
double | 8 | Double |
- WarpperClassInstance.SIZE表示对应基本类型的二进制存储位数;
- WarpperClassInstance.BYTES表示对应基本类型的字节存储位数;
- WarpperClassInstance.MIN_VALUE/MAX表示对应基本类型的最小取值;
- boolean类型采用16位Unicode编码;
// 巨型整数值后加L,强制使用long(int)类型
// Java中整型变量默认为int
int bigValue = 999999999999L;
// 二进制整数以0b或者0B开头
int binaryValue = 0B01101001;
// 八进制整数以0b开头
int ocValue = 013;
// 十六进制整数以0x或者0X开头, a~f不区分大小写
int hexValue = 0XAF;
// Java中浮点数变量默认为double类型,使用float变量,必须在数值后加f或F
float a = 5.12F
// 浮点数还可用科学计数法表示,5.12e2 = 5.12*10-4
包装类(Wrapper Class)
Object类提供包装类封装基本数据类型,使得基本数据类型“对象化”; 所有包装类都使用final修饰,无法继承和重写;
自动装箱(Auto Boxing): 基本数据类型变量—>包装类变量,通过 直接赋值/ new WrapperClass ( primitive )
自动拆箱(Auto Unboxing):包装类变量—>基本数据类型变量 WrapperInstance.xxxValue() ;
自动装箱与自动拆箱实现基本数据类型与包装类对象之间的转换;
包装类实现基本数据类型与字符串转换:
字符串—>基本数据类型: 包装类提供的 Xxx.parseXxx()方法/WrapperClass提供的Xxx(String str)重载构造器
基本数据类型—>字符串:String类提供的重载 String.valueOf()方,Boolean类型也可转换为String变量"true"/"false"
基本数据类型与包装类
- 所有相同包装类对象进行判等操作时,强制使用equals()方法判等;
- 局部变量使用基本数据类型;
- long/Long类型初始赋值时,必须使用大写的L,小写容易与1混淆;
Java String类/字符串
String的不可变性/线程安全
- String类字符串值使用final类型的字符数组存储,因此一旦赋值不可改变;
- 构造方法中使用Array.copyof方法赋值,并开辟内存空间;
- String类使用final修饰符,表示String类不可继承;
- String类提供的所有方法中,有返回String的一律新建一个String对象,防止对原String对象进行修改;
String对象内存分配
字符串常量池:位于常量池中,由String类私有维护,池中元素都是String对象,每个String对象的字面值是 唯一的,由GC回收;
String常量对象创建场合:当String对象第一次常量赋值和调用String对象调用intern()方法时,常量池中创建对应String常量对象;
String str1 = "abc";
String str2 = "abc";
String str3 = str1;
String str4 = new String("abcd");
String str5 = new String("abc");
String对象创建,分为直接常量赋值与new运算符创建;
直接字符串常量赋值
创建对象时,在编译阶段,编译器先去字符串常量池检查是否有String 常量 对象拥有字面值"abc",
- 存在/str2:在栈中创建引用,指向常量池中的Strng常量对象(字面值为"abc");
- 不存在/str1:在常量池中创建匿名Strng对象(字面值为"abc"),在栈中创建引用,指向String常量对象;
使用new运算符创建
创建对象时,程序 先去字符串常量池检查是否有String对象拥有字面值"abc",
- 存在/str5:在栈中创建对象引用,在堆区为实例分配内存,但是字符数组value字段保存常量对象(常量池中)的value字段的引用;
- 不存在/str4:在栈中创建对象引用,在堆区为实例分配内存,在常量池中创建String常量对象,字符数组value字段保存常量对象(常量池中)的value字段的引用;
String类的intern()方法
String str6 = new String("abc");
String a = str6.intern();
String str7 = "xyz";
String b = str7.intern();
str.intern()首先检查常量池中的String常量对象字面值是否有与str.value相等的,若有直接返回对应String常量对象的引用,否则在常量池中创建字面值为str.value的 String常量对象并返回引用;
String判等
- String类判等可用equals方法和等号运算符:
-
- equals()方法检测两个字符串变量/常量是否相等;
- “==”运算符判断两个String对象的引用地址是否相同,即判断引用变量是否指向同一个对象;
String:空串与null
空串是长度为0的字符串,判断方式如下:
if(str.length() == 0)
if(str.equals(""))
null表示String对象为空,用if(str == null)判断;
String、StringBuilder类与StringBuffer类辨析
String类对象不可变,线程安全 【异】
StringBuilder与 StringBuffer都继承AbstractStringBuilder类(类中定义char[] value),字面值均可变【同】;
StringBuffer中主要方法用synchronized加了同步锁,因此 线程安全 【异】 ;
StringBuilder方法没有加同步锁,因此线程不安全 ,但在非多线程场景下,效率高于StringBuilder 【异】 ;
三者适用场景 【异】 :
- 使用String类:适用于字符串不频繁变化的场景,比如常量生命,少量变量运算;
- 使用StringBuilder类:适用于单线程环境下字符串频繁变化的场景;
- 使用StringBuffer类:适用于多线程环境下字符串频繁变化的场景;
★ String对象"+/+="本质
- 在进行连接操作(“+”和 “+=”)时,String每次返回一个新的String实例,而StringBuffer/StringBuilder的append()直接返回this
- String类“+”和 “+=”操作符是Java中唯一重载的两个操作符。这两个操作符都是编译器默认引入了StringBuilder类,最后都调用toString方法返回String对象,StringBuilder临时对象被GC回收,因此效率极为低下;
Java流程控制
- break默认结束所在的循环,在break后紧跟一个标签(该标签在所在循环的外层循环之前定义),直接结束外层循环:
- continue默认跳过所在循环的剩余语句,重新开始所在循环的下一次循环,也可紧跟标签,见代码段;
- return语句与break和continue不同,return直接结束方法,不论return处于多少层循环之内;
outer: // 外层循环,outer作为标识符
for(int i=0; i<5; i++) {
for(int j=0; j<3; j++) {
if(j == 1)
//break outer; // 跳出outer所标识的外层循环
//continue outer // 直接结束outer所标识的外层循环的当次循环下的剩余语句,重新开始下一次循环
}
}
if/else/for/while/do语句必须使用大括号{},即使只有一行代码,杜绝以下形式:
if (condition) statements
使用If...else if...else表达逻辑时,不允许超过3层,否则使用 状态设计模式实现;
缩进强制采用4个空格,禁止使用tab字符;
如果使用tab缩进,必须设置1个tab为4个空格,在eclipse中勾选“insert spaces for tabs”;
Java数组
- Java数组定义及遍历
Java数组定义时通过new运算符分配内存空间,数组大小可为变量;
- 数组初始化时,数字数组所有元素均初始化为0,boolean数组的元素会初始化为false,对象数组的元素初始化为null;
- foreach遍历访问数组时,foreach中的循环变量实际为临时变量,遍历时系统将数组元素依次赋给这个临时变量。
- foreach循环不能改变数组元素的值;
- 除Map外,各类集合通过iterator()方法(实现了Iterable<T>接口)构造一个迭代器从而实现集合遍历;
- Java数组是引用类型,指向堆中创建的真实对象,与数组元素分开存放(类似于C指针,不过C中数组名时数组起始元素地址),故必须先初始化后使用;
- Java"二维数组"实质是一维数组,因为其数组元素是指向一维数组的引用(类似于C中指针的指针);
- Java数组拷贝
数组引用拷贝:数组名赋值,两个数组变量将引用同一个数组;
完整数组拷贝:通过Arrays.copyOf,System.arrayCopy()实现
Java控制台输入输出
控制台输入通过java.util.Scanner类实现;
- String nextLine() // 读取输入的一行内容,包含空白字符(tab/space)
- String next() // 读取输入的第一个单词,过滤空白字符(tab/space)
- int nextInt() / double nextDouble // 读取并转换输入的整数/浮点数,非法输入会抛出异常
System.out.println(Object x),自动调用x的toString()方法;
System.out.printf()用于格式化输出数据, double与float格式化输出均使用%f(与C不同)
Java注释规约/javadoc
- 类/类属性/类方法的注释必须使用Javadoc规范,使用/** */注释,不得使用//注释,类中必须添加作者信息;
- 所有抽象方法/接口中的方法必须使用Javadoc规范,说明返回值,参数,异常说明和方法功能;
- Javadoc注释标记;
- 方法内部单行注释时,在被注释语句上方另起一行,使用//注释;
- 方法内部多行注释时,使用/* */注释,与代码对齐;
javadoc只能对public和protected成员进行文档注释,
javadoc可以通过HTML标签实现对文本内容格式化;
javadoc标签:
@see:允许用户链接其他类的文档;
@version:
@author:作者;
@since:指定代码最早使用的版本
@param:
@return:
@throws:
@Deprecated:指出有些特性已经过时,建议用户不再使用;
package, import
package/包机制
Java引入package/包机制,提供了类的多层命名空间/解决类的命名冲突,类文件管理等问题;
package语句负责将类加入指定package中,否则默认加入default package中;
包名统一使用小写单数形式;
import语句负责导入另一个 package 中的公有类;
- 当两个package中有重名类需要同时使用时,在每个类名之前加上完整的package名以避免冲突;
- import static负责导入static方法;
与C++相比,package/包机制类比于namespace命名空间,import语句类比于using指令;