1 类与对象
1.1 类与对象的关系
属性(成员变量):类似定义变量,但不在方法内
行为(成员方法):类似定义方法,但不含static
1.2 类的创建
对象名.成员变量
对象名.成员方法
如图片所示,在创建类的时候,首先在方法区加载TestDemo2类和Car类,以及其中的成员变量和成员方法
而后执行Car car = new Car(),new Car()创建的对象实例在堆内存中,在栈内存声明的对象变量,car是一个指针,指向堆内存中的对象实例,实际上是一个指向堆内存对象的引用。在堆内存的生命周期当中,只要还有指向其对象的引用,堆内存中的对象就会一直存在
栈内存的局部变量的生命周期只存在于方法内部,会在执行完对应方法后被回收,而堆内存中的变量对象不会自动释放,直到确定没有任何引用指向它才会被垃圾收集器回收
2 构造方法
- 当类没有提供任何构造方法,那么会有一个创建一个无参构造方法,如果已存在有参构造方法,则不会自动创建无参构造
- 构造方法可以重载
3 关键字
3.1 private
- private是一个关键字,也是一个权限修饰符,可以修饰成员,被private修饰的成员只能在本类中才能访问
- private通常用来修饰成员变量,不允许外部直接访问,而是提供对应的set/get方法来间接访问成员变量,这样可以将内部成员隐藏起来,提高代码的安全性、保障数据不受外部损害,并提高代码的内聚性
3.2 this
- this是一个关键字,指向调用的对象,在构造方法中this()必须在代码的第一行,因为当创建一个新的对象时,jvm必须知道执行哪个构造器,不过不放在第一行,jvm就无法确定是否存在其他需要执行的构造函数,且构造函数只能被构造函数调用,因为对象实例只会初始化一次
public class ThisDemo {
public static void main(String[] args) {
new ThisDemoClass(5,6);
}
}
class ThisDemoClass{
int a = 1;
int b = 2;
public ThisDemoClass(int a) {
System.out.println("a = " + a);
}
public ThisDemoClass(int a, int b) {
this(3); //this()方法必须在第一行
this.a = a;
this.b = b;
System.out.print("a = " + a +",b = "+ b);
}
}
this.成员变量
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public int setAge(int age){
this.age = age;
}
this.参数 //调用当前类的构造方法
this.成员方法
public void eat(){
System.out.println(name + "要吃饭");
}
public void sleep(){
// 成员方法(对象方法) 必须使用对象来调用
this.eat();
System.out.println(this);
System.out.println("人要睡觉");
}
3.3 super
- super()用于调用父类的构造方法,所有构造方法第一行默认会有一个super(),但super()和this()
- super.成员方法() super.成员变量,用于访问父类的方法和成员变量
- super() 必须在构造方法的第一行,因为构造函数的目的是初始化对象,子类继承父类,并可能会访问父类的成员变量或方法,所以要在子类可以访问父类之前完成父类对象的初始化
public class super1 { public static void main(String[] args) { Dog dog = new Dog(); dog.eat("狗狗"); } } class Pet{ String name; public Pet(String name) { this.name = name; System.out.println(name); } public void eat(String name){ System.out.println(name + "在吃饭"); } } class Dog extends Pet{ public Dog() { //默认调用父类的无参构造 super("狗"); System.out.println("子类调用父类"); } }
4 代码块
4.1 构造代码块
-
在创建对象时,构造代码块先于构造方法运行
public class CodeBlockDemo { public static void main(String[] args) { new CodeBlockDemo2(); } } class CodeBlockDemo2{ { System.out.println("构造代码块"); } public CodeBlockDemo2(String a) { System.out.println(a); } public CodeBlockDemo2() { this("另一个构造函数"); System.out.println("对象默认构造函数"); } }
4.2 局部代码块
存在于方法中的代码块,由于最先运行并且其中的局部变量等运行完毕后立即销毁,所以提高了栈内存的利用率
5 多态
5.1 继承
- 子类可以通过继承获得父类的所有方法和属性,优点是提高代码复用性,但默认下只有同包子类可以访问,子类不能访问private修饰的方法和属性
- 类与类是单继承关系,整体继承关系呈现树状结构,类之间可以连环继承,但一个类只能继承一个类
public class JiCheng { public static void main(String[] args) { Dog dog = new Dog(); dog.color = "棕黄"; dog.name = "大黄狗"; System.out.print(dog.color + "色的" + dog.name + "在"); dog.shout(); dog.eat(); } } class Pet{ String name; String color; public void shout(){ System.out.println("叫"); } } class Dog extends Pet{ public void eat(){ System.out.println("狗在啃骨头"); } }
5.2 重写
当子类继承父类后,可以实现不同于父类的功能,对于具有相同签名(同名)的方法,子类可以通过重写来改变父类的行为,但重写的方法名、返回的参数类型和传参列表都必须与父类的方法相同
public class OverrideDemo {
public static void main(String[] args) {
OverrideDemo2 overrideDemo2 = new OverrideDemo2();
overrideDemo2.out();
}
void out(){
System.out.println("这是父类的内容");
}
}
class OverrideDemo2 extends OverrideDemo{
@Override
void out() {
// super.out(); //如果包括了super(),则会先执行父类方法,再执行子类的重写内容
System.out.println("这是子类重写的内容");
}
}
5.3 对象数组
public class ObjectArrayDemo {
public static void main(String[] args) {
ObjectArrayDemoCat cat = new ObjectArrayDemoCat("猫",5);
ObjectArrayDemoDog dog = new ObjectArrayDemoDog("狗",8);
ObjectArrayDemoPet[] petArr = new ObjectArrayDemoPet[3];
petArr[0] = cat;
petArr[1] = dog;
for (ObjectArrayDemoPet pet : petArr){
if (pet == null){
break;
}
System.out.println(pet.getName() + "的年龄为" + pet.getAge());
}
}
}
class ObjectArrayDemoPet {
String name;
int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public ObjectArrayDemoPet(String name, int age) {
this.name = name;
this.age = age;
}
}
class ObjectArrayDemoDog extends ObjectArrayDemoPet{
public ObjectArrayDemoDog(String name, int age) {
super(name, age);
}
}
class ObjectArrayDemoCat extends ObjectArrayDemoPet{
public ObjectArrayDemoCat(String name, int age) {
super(name, age);
}
}
6 权限修饰符
本类中 | 子类中 | 同包类中 | 其他类中 | |
---|---|---|---|---|
public | 可以 | 可以 | 可以 | 可以 |
protected | 可以 | 可以 | 可以 | 不可以 |
默认 | 可以 | 同包的子类中 | 可以 | 不可以 |
private | 可以 | 不可以 | 不可以 | 不可以 |
7 接口
7.1 抽象类
7.1.1 基本概念
-
抽象类不能实例化,即无法创建对象
-
抽象类可以使用抽象方法,但只能声明方法,不能实现功能,该方法必须由子类实现,详情代码如下:
public class AbstractDemo {
public static void main(String[] args) {
Dog dog = new Dog();
dog.shout();
dog.sleep();
}
}
abstract class AbstractDemoPet{
abstract void shout();
void sleep(){
System.out.println("睡觉了");
}
}
class Dog extends AbstractDemoPet{
@Override
void shout() {
System.out.println("汪汪汪");
}
}
- 抽象类也可以像普通类一样拥有普通成员变量和方法,也可以使用构造函数完成初始化
7.1.2 抽象类和普通类的区别
- 抽象类更适用于搭建功能的基础框,用于定义一组共有特征的功能,确保子类都能实现特定的功能。而普通类更适用于创建对象实例,用于简单明了、不需要被继承或扩展的功能实现
7.2 接口
7.2.1 接口继承关系
- 与类不同,接口与接口是多继承关系,一个接口可以继承多个接口
public interface AInterface {
void a();
}
interface BInterface {
void c();
}
Java
interface CInterface extends AInterface, BInterface {
void b();
}
7.2.2 接口实现(implments)
- 类与接口是多实现关系,一个类可以实现多个接口,接口与抽象类似,不能用于实例化对象,必须作为高层接口被子类实现功能,具体代码格式接近于继承
public interface Plugin {
void launch();
void run();
void ruin();
}
package q1;
public class Software{
void launch(Plugin plugin) {
plugin.launch();
}
void run(Plugin plugin) {
plugin.run();
}
void uninstall(Plugin plugin) {
plugin.ruin();
}
}
class QQMusic extends Software implements Plugin{
@Override
public void launch() {
System.out.println("启动");
}
@Override
public void ruin() {
System.out.println("结束");
}
}
}
public class Test {
public static void main(String[] args) {
Software software = new Software();
QQMusic qqMusic = new QQMusic();
qqMusic.launch();
qqMusic.ruin();
}
}
7.2.3 接口与抽象类的区别
抽象类 | 接口 | |
---|---|---|
属性 | 无限制 | public静态常量 |
构造方法 | 可选 | 无 |
普通方法 | 可以有普通具体方法 | 必须是public抽象方法 |
子类 | 单继承 | 多继承(接口对接口) |
7.3 @FunctionalInterface
@FunctionalInterface
- @FunctionalInterface 注解表示当前接口为函数式接口
- @FunctionalInterface 注解不是必须的
- @FunctionalInterface 表示当前接口有且仅有一个抽象方法,同时意味着可以使用lambda表达式进行简化表达
7.4 Lambda
7.4.1 概念
- Lambda可以根据任意一个类/接口创建一个匿名内部类,用于替代接口的匿名内部类
- 接口匿名内部类等于接口实现类
7.4.2 语法
-
基本语法1:
(形参类型 变量1…形参类型 变量n)->{
//⽅法体 核⼼逻辑
} - 简化语法2:(⽅法引⽤)
引⽤/对象::⽅法名;
类名::⽅法名;
interface LambdaDemoInterface2 {
int operate(int a, int b);
}
public class LambdaDemo2 {
public static void main(String[] args) {
LambdaDemoInterface2 lambdaDemoInterface2 = (a, b) -> a * b;
//等价于
// LambdaDemoInterface2 lambdaDemoInterface3 = new LambdaDemoInterface2() {
// @Override
// public int operate(int a, int b) {
// return a * b;
// }
// };
int result = lambdaDemoInterface2.operate(10, 20);
System.out.println("结果: " + result);
}
}
8 枚举
8.1基本知识
-
这部分知识点比较碎,我在代码中做出注释
public enum EnumDemo { /** * enum枚举类的第一行代码必须是枚举常量(枚举对象) * 通过反编译class文件可以发现 * 'SUNDAY,MONDAY,TUESDAY;'这一行实际上等于: * private static final EnumDemo SUNDAY = new EnumDemo * private static final EnumDemo MONDAY = new EnumDemo * private static final EnumDemo TUESDAY = new EnumDemo * 所以他们都是被确定过的,无法被更改 */ SUNDAY,MONDAY,TUESDAY; private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public static void main(String[] args) { //😅千万不要这么写,枚举类是不可被实例化的 //EnumDemo enumDemo = new EnumDemo(); //但我们可以通过类直接访问类的对象 EnumDemo sunday = EnumDemo.SUNDAY; sunday.setName("sunday"); System.out.println("通过get/set方法进行传参/读参:" + sunday.getName()); /*枚举的扩展API*/ //通过values()拿到枚举类的全部对象 EnumDemo[] enumArr = EnumDemo.values(); System.out.println("enumArr[]的内容:" + Arrays.toString(enumArr)); //通过valueOf()由在枚举类中查找并返回对应名称的枚举常量 //传送的值必须与对应枚举对象相同(包括大写),否则运行时将会抛出异常 EnumDemo monday = EnumDemo.valueOf("MONDAY"); System.out.println("monday对应的枚举常量名:" + monday.name()); System.out.println("monday对应的对象索引:" + monday.ordinal()); //枚举类的对象数组也可以执行API System.out.println("对象数组:" + enumArr[0].name()); } }
8.2 应用场景
9.泛型
To be continued