面向对象基础
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)