Java 学习笔记(基础)
概述
类别
- Java SE:Java Standard Edition (J2SE)
- Java ME: Java Mobile Edition (J2ME)
- Java EE:Java Enterprise Edition (J2EE)
JDK、JRE、JVM
- JDK:Java Development Kit (Java开发必备)
- JRE:Java Runtime Environment(Java执行环境)
- JVM:Java Virtual Machine(Java虚拟机)
- API :Application Programming Interface(应用编程接口)
程序构造块
-
package:零条或一条,出现在程序最开始的地方
-
import:零条或多条,引入 Java 提供的类(API)
-
class:创建自己的类,公开类的类名跟文件名保持一致
-
main:可执行 Java 程序的入口
- 三个修饰符:public、static、void
- 可接收命令行参数
-
注释
- 行注释://
- 块注释:/*……*/
- 文档注释:/**……*/
- @author 作者
- @param 参数
- @return 返回值
- @throw 可能引发的异常
执行过程
- 编译:javac Test.java
- 执行:java Test (编译生成的 class 字节码文件,命令中没有 .class)
核心语言
语言元素
- 关键字 50个
- 标识符
- 可以是字符、数字、下划线、$,不能以数字开头,不能有 ! 等特殊符号
- 不能是关键字
- 大小写敏感
- 类:首字母大写,如果一个类名由多个单词构成,那么每个单词的首字母都大写, 中间不使用任何的连接符。比如 Person 类,MemberTest 类。
- 方法:首字母小写。如果一个方法由多个单词构成,那么第一个单词的所有字母全 都小写,从第二个单词开始,每个单词的首字母大写。比如 add,addThreeInt。
- 属性:命名约定与方法相同。比如 age,ageOfPerson。
- 包:将公司域名反转作为包名、对于包名 每个字母都需要小写
- 常量:所有单词的字母都是大写,如果有多个单词, 那么使用下划线连接即可。
- 运算符
- 赋值运算符:=
- 算术运算符:+、-、*、/、%
- 关系运算符:>、<、>=、<=、!=
- 短路运算符
- && 短路与
- || 短路或
- 条件运算符:三目运算符 ?:
- 逻辑运算符:&、|、!
- 自增 / 自减运算符:++ / –
- 下标运算符:[]
- 类型转换运算符:()
- 其他运算符
- new
- instanceof
- 位运算符
- 访问成员运算符
- 字面量(直接量)
- 整型字面量
- 100
- 123L 长整型
- 实型字面量
- 9.8F 浮点型
- 3.2E - 3
- 字符字面量
- ‘a’
- ‘\t’
- ‘\105’ 大写字母 E
- 字符串字面量:“hello”
- 布尔型字面量:true、false
- 引用字面量:null
- 类型字面量
- int.class
- String.class
- 整型字面量
- 分隔符
变量和常量
数据类型
-
基本数据类型
-
byte: 占用1个字节,取值范围-128 ~ 127
-
short: 占用2个字节,取值范围-215 ~ 215-1
-
int:占用4个字节,取值范围-231 ~ 231-1
-
long:占用8个字节
-
float:占用4个字节
- 1.1f 字面量才是 float 类型。
-
double:占用8个字节
- 1.1 字面量属于 double 类型,不能直接将 1.1 直接赋值给 float 变量,因为这是向下转型。Java 不能隐式执行向下转型,因为这会使得精度降低。
-
char: 占用2个字节
-
boolean:占用大小根据实现虚拟机不同有所差异
-
-
枚举类型:符号常量
-
引用类型:对象
-
包装类型
-
Byte
-
Short
-
Integer
-
Long
-
Float
-
Double
-
Character
-
Boolean
基本类型都有对应的包装类型,基本类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成。
Integer x = 2; // 装箱 int y = x; // 拆箱
-
-
缓存池
new Integer(123) 与 Integer.valueOf(123) 的区别在于:
-
new Integer(123) 每次都会新建一个对象
-
Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。
Integer x = new Integer(123); Integer y = new Integer(123); System.out.println(x == y); // false Integer z = Integer.valueOf(123); Integer k = Integer.valueOf(123); System.out.println(z == k); // true
-
valueOf():
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
-
字符串
创建字符串对象
- String str = “hello”; str 引用静态区的字符串字面量
- String str = new String(“hello”); str 引用堆上的字符串对象
- 字符串池
String s = "aaa";
(采用字面值方式赋值)- 首先查找 String Pool 中是否存在“aaa”这个对象,如果不存在,则在 String Pool 中创建 一个“aaa”对象,然后将 String Pool 中的这个“aaa”对象的地址返回来,赋给引用变量 s,这样 s 会指向 String Pool 中的这个“aaa”字符串对象
- 如果存在,则不创建任何对象,直接将 String Pool 中的这个“aaa”对象地址返回来, 赋给 s 引用。
- String s = new String(“aaa”);
- 首先在 String Pool 中查找有没有“aaa”这个字符串对象,如果有,则不在 String Pool 中再去创建“aaa”这个对象了,直接在堆中(heap)中创建一个“aaa”字符串对象,然后将堆中的这个“aaa”对象的地址返回来,赋给 s 引用,导致 s 指向了堆中创建的这个“aaa”字符串对象。
- 如果没有,则首先在 String Pool 中创建一个“aaa“对象,然后再在堆中(heap)创 建一个”aaa“对象,然后将堆中的这个”aaa“对象的地址返回来,赋给 s 引用, 导致 s 指向了堆中所创建的这个”aaa“对象。
操作字符串方法
- 字符串长度:length()
- 取字符串:charAt(int)
- 判断两个字符串内容是否相等:equals()
- 连接:concat(String)
- 判断是否以什么开头 / 结尾:startsWith(String); / endsWith(String)
- 模式匹配:indexOf(String, [int]) / lastIndexOf(String, [int])
- 取子字符串:substring(int beginIndex, [int endIndex])
- 修剪字符串左右两边空格:trim()
- 替换:replace(char oldChar, char newChar); / replaceAll(String regex, String replacement)
数组
一维数组
- 初始化
- int[] a = new int[10];
- int[] a = {1, 2, 3, 4, 5};
- 常用属性:a.length
二维数组
- 初始化
- {% raw %} int[][] a = new int[10][5] {% endraw %};
- {% raw %} int[][] a = {{1, 2, 3}, {4, 5, 5}, {6, 7, 8}} {% endraw %};
- 常用属性
- a.length 多少行
- a[i].length 多少列
循环结构
三种循环
- for
- while
- do……while
分支结构
- if……else
- switch……case……default
面向对象
-
面向对象程序设计:OOP
- Object Oriented Programming(简称:OOP):面向对象的程序设计
- Object Oriented Design,(简称:OOD):面向对象设计
-
面向对象程序设计的三大基本特征
- 继承(Inheritence)
- 对象的一个新类可以从现有的类中派生,派生类可以从它的基类那继承方法和实例变量,且派生类可以修改或新增新的方法使之更适合特殊的需求。
- 封装(Encapsulation)
- 将客观事物抽象成类,每个类可以把自身数据和方法只让可信的类或对象操作,对不可信的进行信息隐藏。
- 多态 (Polymorphism)
- 允许不同类的对象对同一消息作出响应。不同对象调用相同方法即使参数也相同,最终表现行为是不一样的。
- 继承(Inheritence)
-
修饰符
- public: 对所有类可见
- protected : 对同一包内的类和所有子类可见,不能修饰类
- default: 默认访问修饰符,在同一包内可见
- private: 在同一类内可见,不能修饰类
访问级别 | 访问控制修饰符 | 同类 | 同包不同类(不含子类) | 同包子类 | 不同包不同类(不含子类) | 不同包子类 |
---|---|---|---|---|---|---|
公开 | public | √ | √ | √ | √ | √ |
受保护 | protected | √ | √ | √ | – | √(注意) |
默认 | default | √ | √ | √ | – | – |
私有 | private | √ | — | — | – | – |
封装(Encapsulation)
- 利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体。数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。用户无需知道对象内部的细节,但可以通过对象对外提供的接口来访问该对象。
public class Person {
private String name;
private int gender;
private int age;
public String getName() {
return name;
}
public String getGender() {
return gender == 0 ? "man" : "woman";
}
public void work() {
if (18 <= age && age <= 50) {
System.out.println(name + " is working very hard!");
} else {
System.out.println(name + " can't work any more!");
}
}
}
继承(Inheritence)
-
继承实现了 IS-A 关系,例如 Cat 和 Animal 就是一种 IS-A 关系,因此 Cat 可以继承自 Animal,从而获得 Animal 非 private 的属性和方法。
-
继承应该遵循里氏替换原则,子类对象必须能够替换掉所有父类对象。
-
Cat 可以当做 Animal 来使用,也就是说可以使用 Animal 引用 Cat 对象。父类引用指向子类对象称为 向上转型 。
Animal animal = new Cat();
多态(Polymorphism)
-
父类型的引用可以指向子类的对象。
People people = new Man();
-
当使用多态方式调用方法时,首先检查父类中是否有 sing()方法,如果没有则编译错误;如果有,再去调用子类的 sing()方法。
Parent p = new Child(); p.sing();
-
强制类型转换
-
向上类型转换(upcast):比如说将 Cat 类型转换为 Animal 类型,即将子类型转换为父类型。对于向上类型转换,不需要显式指定。
Animal animal = new Cat(); animal.sing();
-
向下类型转换(downcast):比如将 Animal 类型转换为 Cat 类型。即将父类型转换为子类型。对于向下类型转换,必须要显式指定(必须要使用强制类型 转换)。
Animal animal = new Cat(); Cat cat = (Cat) animal; cat.sing();
-
抽象类与接口
-
抽象类
- 抽象类和抽象方法都使用 abstract 关键字进行声明。抽象类一般会包含抽象方法,抽象方法一定位于抽象类中。
- 抽象类和普通类最大的区别是,抽象类不能被实例化,需要继承抽象类才能实例化其子类。
-
接口
- 接口是抽象类的延伸,在 Java 8 之前,它可以看成是一个完全抽象的类,也就是说它不能有任何的方法实现。
- 从 Java 8 开始,接口也可以拥有默认的方法实现,这是因为不支持默认方法的接口的维护成本太高了。在 Java 8 之前,如果一个接口想要添加新的方法,那么要修改所有实现了该接口的类。
- 接口的成员(字段 + 方法)默认都是 public 的,并且不允许定义为 private 或者 protected。
- 接口的字段默认都是 static 和 final 的。
-
对比
-
抽象类提供了一种 IS-A 关系,即子类对象必须能够替换掉所有父类对象。接口只是提供一种方法实现契约,并不要求接口和实现接口的类具有 IS-A 关系。
-
一个类可以实现多个接口,但是不能继承多个抽象类。
-
接口的字段只能是 static 和 final 类型的,而抽象类的字段没有这种限制。
-
接口的成员只能是 public 的,而抽象类的成员可以有多种访问权限。
-
重载与重写
-
重载
存在于同一个类中,指一个方法与已经存在的方法名称上相同,但是参数类型、个数、顺序至少有一个不同。
应该注意的是,返回值不同,其它都相同不算是重载。
-
重写
存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法。
- 子类方法的访问权限必须大于等于父类方法;
- 子类方法的返回类型必须是父类方法返回类型或为其子类型。
Object 类
-
==
- 对于原生数据类型来说,比较的是左右两边的值是否相等。
- 对于引用类型来说,比较左右两边的引用是否指向同一个对象,或者说左右两边的引用地址是否相同。
-
equals
-
用于检测一个对象是否等于另外一个对象
public boolean equals(Object obj) { return (this == obj); }
-
-
源代码
package java.lang; public class Object { private static native void registerNatives(); static { registerNatives(); } public final native Class<?> getClass(); public native int hashCode(); public boolean equals(Object obj) { return (this == obj); } protected native Object clone() throws CloneNotSupportedException; public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } public final native void notify(); public final native void notifyAll(); public final native void wait(long timeout) throws InterruptedException; public final void wait(long timeout, int nanos) throws InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException("nanosecond timeout value out of range"); } if (nanos > 0) { timeout++; } wait(timeout); } public final void wait() throws InterruptedException { wait(0); } protected void finalize() throws Throwable { } }
String
String 被声明为 final,因此它不可被继承。
内部使用 char 数组存储数据,该数组被声明为 final,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
String、StringBuffer、StringBuilder
- 可变性
- String 不可变
- StringBuffer 和 StringBuilder 可变
- 线程安全
- String 不可变,因此是线程安全的
- StringBuilder 不是线程安全的
- StringBuffer 是线程安全的,内部使用 synchronized 进行同步,由于同步的原因较之 StringBuilder 慢