面向对象基础
class和instance是模板和实例的关系
class定义的field, 在每个instance中都会含有独立的field
- 指向
instance的变量, 都是引用变量
方法
field的修饰符, 由public改为private后, 不可直接访问, 需要通过method进行访问
修饰符 方法返回类型 方法名(方法参数列表) {
若干方法语句;
return 方法返回值
}
this
- 始终指向当前实例
- 如果没有命名冲突可以省略
this, 如果有局部优先级更高
方法参数
- 调用方法时, 必须按照参数规则一一传递
- 使用
...进行可变参数
- 如果0个参数时, 实际接收的是一个空数组
- 基本类型参数的传递是调用值的复制
- 引用类型参数的传递是指针的复制, 改变外边的值会影响到内部值
public class Hello {
public String name;
public int age;
public static void main(String[] args) {
City bj = new City();
String n = "aaaaaa";
bj.setName(n);
n = "bbbbbb"; // 这里是新开了内存地址, 并不影响指针指向地震
System.out.println(bj.getName()); // aaaaa
}
};
class City {
public String name;
public String getName () {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
构造方法
- 方法名就是类型, 没有返回值
- 构造方法没有参数限制
- 内部可以执行任意语句
public class Hello {
public String name;
public int age;
public static void main(String[] args) {
City bj = new City("beijing");
City wh = new City();
System.out.println(bj.getName()); // aaaaa
System.out.println(wh.getName());
}
};
class City {
public String name;
public City() {
}
public City(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
- 可以根据不同参数, 执行不同构造函数
- 引用类型默认参数
null, 数值类型int默认参数0, 布尔类型默认值false
- 使用this(...)可以调用其他构成方法
方法重载
继承
继承树
- 没有写
extend默认继承自Object
- 子类无法访问父类的
private的字段和方法
protected
- 子类可以访问父类的
protected的字段和方法
protected修饰符, 把访问权限控制在继承树内
super
super表示父类
- 在构造函数中, 需要添加
super()
- 子类不会继承任何父类的构造方法
向上转型
Person p = new Student();
- 可以向上转型, 转化为更高层次
向下转型
Person p1 = new Student();
if (p1 instanceof Student) Student s = (Student) p1;
区分继承和组合
class Student extends Person {
protected Book book;
protected int score;
}
多态
- 方法名相同, 参数或者返回值不同是,
Overload写一个新方法
- 如果全部相同(方法名, 参数, 返回值), 就是覆写
Override
@Override用来检查覆写是否成功
- Java中的方法调用是基于在实际运行时的方法调用, 而非变量的声明类型
- 如果再子类中需要调用父类 使用
super进行调用
final标记的方法不允许被重写
final class Person {
}
class Student extends Person { // The type Student cannot subclass the final class Person
}
- final修饰的类, 不能被继承
- final修饰的字段, 初始化后, 不能改变
抽象类
- 如果仅仅是为了让子类覆写, 定义抽象方法
abstract.
abstract class Person {
public abstract void run();
}
- 只有抽象类才能有抽象方法
- 抽象类无法被实例化
- 子类必须完全覆写所有的抽象方法
接口
- 只有抽象方法的抽象类, 可以更改为
interface
- 接口没有字段, 至于抽象方法, 全部默认为
public abstract
class Student implements Person, Hello { // 实现了两个interface
...
}
- 一个类可以继承多个接口
- 接口可以继承接口
default方法, 可以不用所有子类都继承
public class Hello {
public String name;
public int age;
public static void main(String[] args) {
Person a = new Student();
a.run();
}
};
class Man {
}
interface Person {
String getName();
default void run() {
getName();
}
}
class Student extends Man implements Person {
@Override
public String getName() {
System.out.print("aaa");
return "aaa";
}
}
- 通过
default, 可以给接口添加方法, 而不用所有子类都添加方法
总结
- 所有公共逻辑放到
abstract class中, 具体实现在子类.
- 接口表示更高层次的抽象程度.
- 可以通过先继承, 再使用一个接口, 使用的时候用接口引用, 因为接口比抽象类更抽象
静态字段和静态方法
- 静态字段共享一个空间
- 调用实例方法, 必须通过一个实例, 但是静态方法就不用
- 静态方法属于类, 没有
this关键字
- 静态方法, 经常用于工具类
- 抽象类的静态字段, 必须是
final
包
- 命名空间, 用包(package)名, 进行区分
- 包没有继承关系, java.util和java.util.zip是不同的包,两者没有任何继承关系。
- 注意包的安放目录.
包作用域
- 位于同一个包作用域的类, 可以访问作用域的字段和方法
- 不用
public, protected, private修饰的字段和方法就是包作用域
- 包机制就是为了避免命名冲突
作用域
- 定义
public的class, interface可以被其他类任意访问
- 定义
public的field, method可以被其他类访问, 前提是可以访问到这个类
- 定义
private的field, method无非被其他类访问
- 嵌套类可以访问
private
- 定义
protected的field, method可以被子类访问, 以及子类的子类
- 包作用域是指一个类允许访问同一个
package中没有public, private修饰的class, 以及没有public, private与protected修饰的field, method
final
final与访问权限不冲突
- 修饰
class阻止被继承
- 修饰
method阻止子类被覆写
- 修饰
field阻止字段被重写
- 修饰局部变量阻止被重写
最佳实践
- 尽量不要public, 少暴露字段和方法
- 方法定义为
package权限, 有助于测试
- 一个
.java文件只能包含一个public, 并文件名和public类的名称一致
classpath和jar
- 用来指示JVM如何搜索
class
- 没有传入的环境变量, 默认为
.
- 不需要把Java核心类库添加到classpath中!
jar 包
- 如果要执行一个jar中的class中, 就把jar的目录放到classpath中
模块
- jar是存放class的容器, 并不关心class之间的依赖关系
- 自带"依赖关系"的class容器, 就是模块
- java.base是根模块
JAVA核心类
字符串和编码
- String
- 保持绝对的不变性
- 引用类型, class, 特殊, 可以用"..."表示
- 内部使用char[]实现
- 字符串比较
- equals()进行比较
- 编译期把所有相同字符串当做一个对象放入常量池
CharSequence是String的父类
- 搜索: indexOf lastIndexOf startsWidth endsWidth
- 提取: substring(2), substring(2, 4)
- 去除首位
- trim, strip
- isEmpty, isBlank
- 替换
- 分割字符串: split
- 拼接: join
- 类型替换
- 任意类型 => 字符串:
valueOf()
- Integer.parseInt()
- Boolean.parseBoolean()
- String 和 char[] 类型可以互相转换
- 为了保证不变形, 我们需要复制, 而不是直接引用
- 编码
- Java的
String和char在内存中总是以Unicode
- 转换编码就是
String和byte[]转换
- 转换byte[]时, 始终优先考虑
UTF-8
StringBuilder
- 可变对象, 可以预分配缓冲区, 这样新增字符时, 不会创建新的临时对象
- 可以进行链式操作
- java编译器进行编译时就自动把多个连续的
+操作编码为StringConcatFactory的操作, 自动进行+操作的优化
StringBuffer是早期的一个线程安全版本, 同步保证多个线程, 但是同步会带来执行速度下降
StringJoiner
包装类型
- 基本类型:
byte, short, int, long, boolean, float, double, char
- 引用类型:
class, interface
- 基本类型不能赋值为null
- 每种类型都有对应的引用类型:
Boolean, Byte, Short, Integer, Long, Float, Double, Character
- Auto Boxing
- 不变类
- 两个Integer对比, 应该是
equals()进行对比
- 静态工厂方法: 创建新对象的静态方法. 例如:
Integer.valueOf()
- 进制转换:
- Integer.parseInt("100", 16)
- Integer.String(100, 16)
- Integer.toHexString(n): 自动把整数转坏为十六进制
- 计算机中, 都是二进制存储, 数据的显示和存储要分离
- 处理无符号整型:
Byte.toUnsignedInt()
- 带有符号
-126 -> 127
- 无符号
0 -> 255
- short无符号->int; int无符号->long
JavaBean
- 有读有写: 属性
- 只读不写: 只读属性
Introspector可以枚举JavaBean的所有属性
enum
- 编译器自动检查某个值在枚举的集合内, 并且, 不同用途的枚举需要不同的类型类来标记
- 比较: 直接用
==
- 和其他class没有任何区别
- 方法:
.name(): 返回常量名
.ordinal(): 返回常量顺序
- 可以给每个枚举常量添加字段
- 每一个枚举类型所代表的属性都是一个实例
- 使用toString变得更加具有输出性
- 天生配合switch, 记得加上
default
enum Weekday {
SUN(0, "星期日"), MON(1, "星期一"), TUE(2, "星期二"), WED(3, "星期三"), THU(4, "星期四"), FRI(5, "星期五"), SAT(6, "星期六");
public final int dayValue;
public final String chinese;
private Weekday(int dayValue, String chinese) {
this.dayValue = dayValue;
this.chinese = chinese;
}
@Override
public String toString() {
return this.chinese;
}
}
BigInteger
- 运算时只能用实例方法
- 可以和
long相互转换, 超过范围报异常.
- 转换方法:
byteValue, shortValue, intValue, longValue等
- 转变
float超范围, 返回: Infinity
.longValueExact保证转换正确性
BigDecimal
- 表示任意大小, 且精度完全准确的浮点数
- 使用`.scale()
- 表示小数的位数
- 如果返回负数, 表示是个整数, 并且末尾有几个0
.stripTrailingZeros()去除小数位的0
.setScale(位数, 截断方式): 按照指定位数进行截断
- 除不尽的时候, 就需要进行一个截断
BigDecimal d1 = new BigDecimal("123.456");
BigDecimal d2 = new BigDecimal("23.1123");
BigDecimal d3 = d1.divide(d2, 2, RoundingMode.HALF_UP);
divideAndRemainder(): 获得商和余数
compareTo(): 进行比较
- 比较的时候, 不但要求值相等, 小数位数也相等
- 根据大小返回. 负数, 整数, 0
- 也从
Number继承, 并不可变
常用工具类
- Math: 数学工具
abs(), max()...
.PI
Math.random(): 0 <= x < 1
StrictMath: 保证各个平台计算结果一致
Math: 针对各个平台优化速度
- Random: 创建伪随机数
- .nextInt(): 随机数
- .nextInt(10): [0, 10]之间的int
- 不指定种子会把当前时间戳作为种子
- 种子相同, 随机数序列相同
- SecureRandom: 获得不可预测的安全随机数
疑问
关于环境变量啥的, 该怎么区分
- /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java_home
- /Library/Java/JavaVirtualMachines/jdk-13.0.2.jdk/Contents/Home
- 放弃了, 始终没有找到
jmod这个命令在哪
语法
double y = 10.1; long n = (long) y
sr = new SecureRandom; sr.nextBytes(buffer)