JavaWeek1-方法构造继承,字符串和可变数组
方法
方法 是程序中最小的执行单元 .
内存分配
- 堆 : 方法运行时使用的内存 , 方法进栈运行 ; 运行完毕出栈 .
- 堆 : 对象
new
实例化时都在堆内存中开辟了一个小空间 , 用于存储类的成员变量和成员方法的地址 , 方法地址指向方法区 . - 方法区 : 字节码文件加载时进入的内存 , 存储可以运行的
class
文件 , 在对象实例化后被首先加载类文件 .
当 JVM
加载类的 class
字节码时 , 会将类的 元数据 存储在方法区 .
元数据 包括 类的结构信息 : 字段、方法、构造方法的定义 ; 静态变量 ;
常量池 .
-
本地方法栈 :
JVM
在使用操作系统功能时使用 . -
寄存器 : 供给
CPU
使用 .
引用数据类型
基本数据类型声明语句被调用时在堆中开辟一个空间用于存储数据 . 变量中存储真实数据 .
如数组等通过 new
关键字得到的变量均属于引用数据类型 .
public class master {
public static void main (String[] args) {
int[] arr = {1, 2, 3};
}
}
栈内存中 , 变量 arr
指向堆中存储 1, 2, 3
的内存空间地址 .
Student student1 = new Student();
STudent student2 = student1;
/* 将student1的值(指向堆内存的地址)赋给student2
* 两个引用指向同一个对象/堆地址
* 对两个引用的修改实际上改变的是同一个对象的值
*/
类关系
-
关联 : 代表了一种使用关系 , 即一种类使用另一种类的功能 , 但彼此之间没有包含关系 .
-
弱拥有 / 聚合 : 整体和部分可以独立存在的包含关系 .
-
强拥有 / 组合 : 整体和部分紧密相关 , 部分不能脱离整体独立存在 .
-
继承 : 一个类继承另一个类的属性和方法 . 被继承的类称为父类或基类 , 继承的类称为子类或派生类 .
构造器
构造器(Constructor)是一种特殊的方法,用于在创建对象时初始化对象的状态。
构造器的名称必须与定义它的类名保持一致 , 且没有返回类型 .
构造器允许重载 , 使用 new
关键字创建对象时自动调用 .
public class Person {
String name;
int age;
public Person() {
this.name = "Unknown";
this.age = 0;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 打印信息的方法
public void printInfo() {
System.out.println("Name: " + name + ", Age: " + age);
}
public static void main(String[] args) {
Person person1 = new Person();
person1.printInfo(); // 输出: Name: Unknown, Age: 0
Person person2 = new Person("Alice", 30);
person2.printInfo(); // 输出: Name: Alice, Age: 30
}
}
如果没有为类定义任何构造器 , 编译器会自动提供一个默认的无参构造器 .
构造器链
如果有多个结构类似的构造器 , 程序员希望在一个构造器中调用另一个构造器以避免重复代码 .
this
关键字是一个引用变量 , 它指向当前正在执行的实例 , 是方法调用者的地址值 . 可以在类中用以区分局部变量和成员变量 , 调用本类方法 , 实现链式调用和匿名内部类引用等 .
public class Person {
private String name;
private int age;
public Person setName(String name) {
this.name = name;
return this; // 返回当前对象
}
public Person setAge(int age) {
this.age = age;
return this; // 返回当前对象
}
public void printInfo() {
System.out.println("Name: " + this.name + ", Age: " + this.age);
}
public static void main(String[] args) {
Person person = new Person().setName("Alice").setAge(30);
person.printInfo();
}
}
main
方法允许放在任何一个类中,因为main
方法只是一个静态方法,它的位置并不会影响其作为程序入口点的功能。
String
类 字符串
创建
- 直接赋值 :
String XX = "XXX";
- 构造 :
String XX = new String();
String XX = new String(String/char[]/byte[]);
StringTable 字符串常量池
串池位于堆内存中 , 当主方法使用直接赋值创建字符串对象时 , 串池会创建一个常量内存空间 , 且将其地址值传递给字符串对象 .
-
再次将该常量赋值给新的对象时会直接将地址值传递给它 , 不会再创建空间 .
- 当使用双引号直接赋值时 , 系统会检查该字符串在串池中是否存在 , 如不存在则创建新的空间 ; 如存在则复用该空间 .
public class StringDemo {
public static void main(String[] args) {
String s1 = "abc";
String s2 = "abc";
}
}
构造方式创建字符串对象时 , 不论每次传递参数 是否相同 , 每一个对象都指向堆内存中不同地址的空间 . 每一次 new
都在堆中创建新空间 .
成员方法
==
运算符比较 基本数据类型的数据值 或 引用数据类型的地址值 .
boolean equals();
:
boolean result = s1.equals(s2);
boolean equalsIgnoreCase(); // 不区分大小写
public String substring();
/* 截取以单个参数索引为开始的字符串
* 或截取以第一参数索引为开始, 第二参数索引为结束的字符串
*/
public char[] toCharArray(); // 将字符串转化为字符数组
StringBuilder
StringBuilder
可以看作是一个容器 , 创建后里面的内容是可变的 , 可以提高字符串的操作效率 .
构造
public StringBuilder();
public StringBuilder(String str);
成员方法
public StringBuilder append(...);
/* 添加转换成字符串的数据并返回对象本身
* 如添加<int>123 -> "123"
* 可以使用链式编程
*/
public StringBuilder reverse();
// 反转容器内容
public int length();
// 返回字符出现的个数
public String toString();
// 将StringBuilder对象转换成String对象
StringJoiner
StringJoiner
在 JDK8
后出现 , 类似于StringBuilder
, 可以控制多次添加数据时的间隔和左右边界格式 .
构造
public StringJoiner(间隔符);
public StringJoiner(间隔符, 起始符, 结束符)
成员方法
public StringJoiner add(...);
/* 添加字符串数据并返回对象本身
* 同样可以使用链式构造
*/
public int length();
public String toString();
拼接原理
如果是多个常量字符串拼接 , 则在编译时触发字符串优化机制 , 在串池中直接存储拼接后的字符串值 .
-
如果若干个常量和变量拼接 , 则先经由串池创建其中的所有常量 , 在堆内存中
-
JDK8
前 , 在包含变量的拼接字符串中每个+
运算符至少在堆内存中对应创建两个内存空间StringBuilder
和String
.
new
创建一个
StringBuider
对象 , 经过
append
,
toString
等操作再得到字符串 , 这个字符串值是由
StringBuilder
对象
new
创建得到的 , 在堆内存中拥有独立的地址 , 并传递该地址值给栈中变量 .
String s1 = "a";
String s2 = s1 + "b"; <=> String s2 = new StringBuilder().append(s1).append("b").toString();
Random.nextXX()
Scanner scanner = new Scanner(System.in);
XXX XX = scanner.next();
psvm + tab
sout + tab
alt + insert
alt + shift + (+=) | (-_)
ArrayList
类 集合 可变数组
集合储存的数据类型是 引用数据类型 和 包装类的基本数据类型 .
构造
ArrayList<数据类型> 实例名 = new ArrayList<>(初始容量);
/* 从现有集合构造
* ArrayList 是 List 接口的一个实现类
*可以使用 List 接口的其他实现类构造 ArrayList
*/
List<数据类型> 实例名1 = new LinkedList<>();
ArrayList<数据类型> 实例名2 = new ArrayList<>(实例名1);
成员方法
添加元素 add
list.add();
/* 将一个参数追加到列表末尾或
* 在第一参数索引处插入第二参数
*/
删除元素 remove
数据类型 变量名 = list.remove();
/* 删除参数索引位置的元素且
* 返回被删除的元素
*/
修改元素 set
数据类型 变量名 = list.set();
/* 替换第一参数索引处的元素且
* 返回被替换的元素
*/
获取元素 get
数据类型 变量名 = list.get();
// 返回列表中参数索引位置的元素
查询列表 和 其他成员函数
int size = list.size();
boolean empty = list.isEmpty();
boolean haveElement = list.comtain(element);
// 检查列表是否包含参数元素
list.clear();
int index = list.indexOf(element);
/* 返回列表中首次出现参数元素的索引
* 若不存在则返回-1
*/
int index = list.lastIndexOf(element);
// 返回最后出现的元素的索引
List<数据类型> sub = list.subList(element1, element2);
// 返回从第一参数索引到第二参数索引范围的子列表
包装类
ArrayList
是一个泛型类,它只能存储对象 , 基本数据类型不是对象 , Java
提供了基本数据类型的包装类 , 包装类将基本数据类型封装为对象 .
byte --- Byte
short --- Short
char --- Character
int --- Integer
long --- Long
float --- Float
double --- Double
boolean --- Boolean
泛型
泛型是指在编程语言中支持类型参数化的一种机制 , 核心在于类型参数化 , 即在定义类、接口或方法时 , 使用占位符 ( 通常用大写字母表示 ) 来代表具体的类型 . 这些占位符在实际使用时会被具体的类型所替代 .
public class Box<T> {
private T content;
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
static
静态
静态变量
类变量加入 static
关键字 , 当实例对象为该变量赋值后 , 所有对象共享值 . 同时可以通过 类名.变量名 直接调用该变量 .
在包括静态变量的类执行后 , 类的 class
字节码文件在方法区加载 , 同时在堆内存中创建了一个静态区单独存放静态变量 . 静态变量随着类的加载而加载 , 优先于对象出现 .
静态方法
静态方法只能访问静态变量和静态方法 ; 非静态方法可以访问所有成员变量和成员方法 .
this
表示当前方法调用者 ( 对象 , 实例等 ) 的地址值 , 由虚拟机赋值 . 成员变量共享静态方法 , 静态方法不具体针对任何一个对象 , 所以静态方法没有 this
关键字 .
类规范
Javabean
类 : 用于描述一类具体事物的类 . 含有一个或多个成员变量 , 空参构造 , 实参构造 , 针对每个成员变量的 get()
和 set()
方法等 .
测试类 : 用于编写和执行测试代码 , 带有 main
方法的类 , 是程序的入口 .
工具类 : 用于封装一系列静态方法 , 提供与特定业务逻辑无关的基础功能,便于代码复用和维护 .
- 工具类通常私有化构造方法 , 不允许外界创建实例化对象 ; 成员方法定义为静态
static
, 便于调用 .
extends
继承
当类之间存在共性内容 , 子类是父类的一种 , 我们考虑使用继承来优化代码 . 子类可以使用父类的变量和方法 .
public class A extends B {
...
} // A称为子类, B称为父类
Java
只支持单继承 , 不支持多继承 , 但支持多层继承 . 单继承 : 一个子类继承一个父类 .
Object
类 : 每一个类都直接或间接的继承于 Object
类 , 如果当前类没有继承关系 , 则虚拟机会隐式构造一个继承关系 extends Object
.
super
父类引用
super
用于指示编译器调用父类方法或构造器 , super
调用构造器的语句必须是子类构造器的第一条语句 .
如果子类构造器没有显式调用父类的构造器 , 编译器将自动调用父类的无参构造器 ; 如果父类没有无参构造器且子类构造器没有显式调用父类的其他构造器 , 编译器将报错 .
// Employee类中的getSalary方法在Manager子类中...
public double getSalary(){
double baseSalary = super.getSalary();
return baseSalary + this.bonus;
}
// 调用Employee父类的含参构造器的情况
public Manager(String name, double salary, int year, int month, int day){
super(name, salary, year, month, day);
this.bonus = 0;
}
调用与修饰词 : 子类不能直接调用父类的构造器 ; 子类可以调用父类所有的成员变量 ; 子类不能调用父类经过 private
修饰的成员方法 .
继承层次 : 由一个公共父类派生的所有子类和间接子类的集合 .
继承链 : 在继承层次中从某个类到其最高父类的路径被称为该类的继承链 .
final
继承阻止
不允许扩展的类称为 final
类 . final
类的所有方法自动成为 final
方法 .
成员方法也可以被声明为 final
, 子类无法覆盖这个方法 .
public final class Executive extands Manager{
...
} // 由Manager继承的Executive类不允许被继承