Java 知识点

classes and objects 类与对象

  • Object(对象):对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
    An object is an instance of a class (not a girlfriend), with states and behaviors. For example, a dog is an object, and its state includes: color, name, breed; Behaviors include wagging the tail, barking, eating, etc.

  • Class(类):类是一个模板,它描述一类对象的行为和状态。
    A class is a template that describes the behavior and state of a class of objects

  • Java中有一个特殊的类,叫做Object类,它是所有类的父类,一个类被定义后,如果没有指定继承的父类,那么默认父类就是Object类。
    There is a special class in Java called the Object class, which is the parent class of all classes. After a class is defined, if no inherited parent class is specified, the default parent class is the Object class.


attributes and methods 属性与方法

Attributes 属性

Attributes(属性):用来描述具体某个对象的特征。描述的是对象的状态信息,比如一条狗的属性就有颜色,名字,品种,通常以变量的形式进行定义。
Used to describe the characteristics of a specific object. It describes the state information of an object, such as the color, name, and breed of a dog, which are usually defined in the form of variables.

public class Dog(){
	//以下三个都是狗狗的属性,
	//这三个东西也叫做变量(variable)
	String name;  
	String color;
	String type;
}

变量通常分为成员变量和局部变量

成员变量 member variable

在类(class)中, 方法体之外定义的变量称为"成员变量" 。In a class, variables defined outside the method body are called “member variable”.

  • 成员变量定义在类体中,在整个类中都可以被访问。Member variables are defined in the class body and can be accessed throughout the entire class.

  • 成员变量分为类变量和实例变量,实例变量存在于对象所在的堆内存中。创建对象后才能访问的变量称为实例变量。Member variables are divided into class variables and instance variables, and instance variables exist in the heap memory where the object is located. Variables that can only be accessed after creating an object are called instance variables.

  • 成员变量有默认初始化值。Member variables have default initialization values

  • 成员变量的权限修饰符可根据需要,选择任意一个。Permission modifiers for member variables can be selected as needed.

局部变量

定义在方法内,代码块内的变量称为局部变量。Variables defined within a method and within a code block are called local variables.

  • 局部变量定义在局部范围内。Local variables are defined within a local range

  • 局部变量存在于栈内存中。Local variables exist in stack memory

  • 作用范围结束,变量空间自动释放。At the end of the scope, the variable space is automatically released

  • 局部变量无默认值,每次必须显示初始化。Local variables have no default values, initialization must be displayed every time

  • 局部变量声明时不指定权限修饰符。Do not specify permission modifiers when declaring local variables.

Method 方法

方法也成为函数,定义在类中,用来描述对象(Object)的一些行为。
Method also calls a function, defined in a class to describe some of the behavior of an object.

instantiation and constructors 实例化和构造函数

instantiation 实例化

在Java语言中使用new关键字创建/构造对象的过程叫做类的实例化,The process of creating/constructing objects using the new keyword in the Java language is called class instantiation.
通俗点就是,实例化:使用关键字new来创建对象。
比如:

Dog dog = new dog();

在new的时候会自动调用Dog类中的构造方法 (constructor), 来进行成员变量(Member variable)的初始化。 这里的Dog(大写的)是类名,dog(小写的)是引用变量名

constructors 构造函数

构造方法负责对象的初始化工作,为实例变量赋予合适的初始值。
The construction method is responsible for initializing objects and assigning appropriate initial values to instance variables.
构造函数必须满足以下的语法规则:

  • 方法名与类名相同
  • 没有返回类型
  • 不能被static,final,native,abstract,synchronized修饰,不能被子类继承
    比如:
public class dog{
	String name;
	String color;
	
	//不带参数的构造函数,
	//就是dog后面的()里没有东西
	public dog(){     
		this.color = "white";
	}

	//带参数的构造函数
	public dog(String name,String color){
		this.name = name;
		this.color = color;
	}

	//不是构造函数,有返回值
	public String dog(String name){
		return name;
	}
}

access modifiers 访问修饰符

Java中,可以使用访问修饰符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。

  • private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类
  • default (即什么也不写,不使用任何关键字): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
  • protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
  • public : 对所有类可见。使用对象:类、接口、变量、方法

static methods 静态方法

static修饰的静态方法会随着类的定义而被分配和装载入内存中,也就是被static修饰的静态方法会先被执行。
静态方法不能引用非静态的,因为在静态方法执行时,根本无法从内存中找到非静态的代码块(因为它们比静态的晚加载)。
Static modified static methods will be allocated and loaded into memory according to the class definition, meaning that static modified static methods will be executed first.
Static methods cannot reference non-static code blocks because they cannot be found from memory during static method execution (because they load later than static code blocks).


immutables

在创建状态后无法改变其状态的对象称为不可变对象。An object whose state cannot be changed after being created is called an immutable object.

存在的意义:

  • 并发编程,线程安全。

  • 无法修改,避免副作用


references and null


generics 泛型

常见泛型参数名称有如下:

  • E:Element (在集合中使用,因为集合中存放的是元素)
  • T:Type(Java 类)
  • K:Key(键)
  • V:Value(值)
  • N:Number(数值类型)
  • ?:表示不确定的java类型

泛型的类型

泛型其实就是参数化类型,即给类型指定一个参数,然后在使用时再指定此参数具体的值,那样这个类型就可以在使用时决定了。
Generics are actually parameterized types, which means assigning a parameter to a type and then specifying the specific value of the parameter when you use, so that the type can be determined during use.

为什么使用泛型

1. 保证了类型的安全性。Ensuring the security of the type.

在没有泛型之前,从集合中读取到的每一个对象都必须进行类型转换,如果不小心插入了错误的类型对象,在运行时的转换处理就会出错。
比如:没有泛型的情况下使用集合:

public static void noGeneric() {
 
ArrayList names = new ArrayList();
 
names.add("mikechen的互联网架构");
 
names.add(123); //编译正常
 
}

有泛型的情况下使用集合:

public static void useGeneric() {
 
ArrayList<String> names = new ArrayList<>();
 
names.add("mikechen的互联网架构");
 
names.add(123); //编译不通过
 
}

有了泛型后,定义好的集合names在编译的时候add(123)就会编译不通过。
相当于告诉编译器每个集合接收的对象类型是什么,编译器在编译期就会做类型检查,告知是否插入了错误类型的对象,使得程序更加安全,增强了程序的健壮性。
Telling the compiler what type of object each collection receives, and the compiler will perform a type check during compilation to inform whether the wrong type of object has been inserted, making the program safer.

2. 消除强制转换 Eliminate forced conversion

以下没有泛型的代码段需要强制转换:

List list = new ArrayList();
 
list.add("hello");
 
String s = (String) list.get(0);

当重写为使用泛型时,代码不需要强制转换:

List<String> list = new ArrayList<String>();
 
list.add("hello");
 
String s = list.get(0); // no cast

3. 避免了不必要的装箱、拆箱操作,提高程序的性能 Avoiding unnecessary boxing and unboxing operations, improving program performance
泛型变量固定了类型,使用的时候就已经知道是值类型还是引用类型,避免了不必要的装箱、拆箱操作。

object a=1;//由于是object类型,会自动进行装箱操作。
 
int b=(int)a;//强制转换,拆箱操作。这样一去一来,当次数多了以后会影响程序的运行效率。

使用泛型后:

public static T GetValue<T>(T a)
 
{
  return a;
}
 
public static void Main()
 
{
  int b=GetValue<int>(1);//使用这个方法的时候已经指定了类型是int,所以不会有装箱和拆箱的操作。
}

4. 提高代码的复用型 Improve code reusability

泛型通配符 Generic wildcard

Java泛型的通配符是用于解决泛型之间引用传递问题的特殊语法, 主要有以下三类:

// 1:表示类型参数可以是任何类型
 
public class Apple<?>{} 
 
// 2:表示类型参数必须是A或者是A的子类
 
public class Apple<T extends A>{} 
 
// 3: 表示类型参数必须是A或者是A的超类型
 
public class Apple<T supers A>{}
  1. 无边界的通配符(Unbounded Wildcards), 就是<?>, 比如List<?>
    无边界的通配符的主要作用就是让泛型能够接受未知类型的数据.

  2. 固定上边界的通配符(Upper Bounded Wildcards),采用<? extends E>的形式
    使用固定上边界的通配符的泛型, 就能够接受指定类及其子类 类型的数据。
    要声明使用该类通配符, 采用<? extends E>的形式, 这里的E就是该泛型的上边界。
    注意: 这里虽然用的是extends关键字, 却不仅限于继承了父类E的子类, 也可以代指显现了接口E的类

  3. 固定下边界的通配符(Lower Bounded Wildcards),采用<? super E>的形式
    使用固定下边界的通配符的泛型, 就能够接受指定类及其父类类型的数据.。
    要声明使用该类通配符, 采用<? super E>的形式, 这里的E就是该泛型的下边界.。
    注意: 你可以为一个泛型指定上边界或下边界, 但是不能同时指定上下边界。


overloading vs overriding 重载与重写

重载 overload

在一个类中同名的方法如果有不同的参数列表(参数类型不同、参数个数不同甚至是参数顺序不同)则视为重载。同时,重载对返回类型没有要求,可以相同也可以不同,但不能通过返回类型是否相同来判断重载。
例如:

public class Father {
	
	/**
		这两个方法相同但是参数列表也就是sayHello后面的()
		里的东西不一样,叫做重载overload
	*/

    public void sayHello() {
        System.out.println("Hello");
    }

    public void sayHello(String name) {
        System.out.println("Hello" + " " + name);
    }
}
  1. 重载Overload是一个类中多态性的一种表现 Overload is a manifestation of polymorphism in a class
  2. 重载要求同名方法的参数列表不同(参数类型,参数个数甚至是参数顺序不同) Overloading requires different parameter lists for methods with the same name (parameter type, number of parameters, and even parameter order)
  3. 重载的时候,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分 When overloading, the return value type can be the same or different. So, we cannot differentiate overloaded functions with return types.

重写 override

从字面上看,重写就是 重新写一遍的意思。其实就是在子类中把父类本身有的方法重新写一遍。子类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中的某个方法,所以在方法名,参数列表,返回类型(除过子类中方法的返回值是父类中方法返回值的子类时)都相同的情况下, 对方法体进行修改或重写,这就是重写。但要注意子类函数的访问修饰权限不能少于父类的。
例如:

public class Father {

    public void sayHello() {
        System.out.println("Hello");
    }
}

class Son extends Father{
		
	//注意重写会有这个@override
    @Override
    public void sayHello() {
       
        System.out.println("hello by ");
    }

}
  1. 发生在父类与子类之间
  2. 方法名,参数列表,返回类型(除过子类中方法的返回类型是父类中返回类型的子类)必须相同
  3. 访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private) The restriction on access modifiers must be greater than the access modifiers of the overridden method
  4. 重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常

getters, setters and encapsulation 封装

封装思想 encapsulation

什么是封装?举个例就像在小卖铺买的零食一样,零食都有包装,将零食与外界隔离开来,避免零食污染不可食用,这就是封装的思想。

如何封装

  1. 属性私有化(private);

  2. 提供给外部一个公共给属性赋值的方法:getter 和 setter 方法。

代码演示:

/**
 * @author zc
 * @date 2021/10/22 10:19
 * java 封装测试类:StudentTest
 * main(String[] args):主程序运行入口
 */
public class StudentTest {
    public static void main(String[] args) {
        // 创建学生类 Student 实例化对象 student
        Student student = new Student();
        // 通过封装的 setter 方法给学生 student 属性 name 赋值
        student.setName("张三");
        // 通过封装的 setter 方法给学生 student 属性 age 赋值
        student.setAge(-10);
        // 通过封装的 getter 方法打印学生 student 属性 name age 信息
        System.out.println("name=" + student.getName()+",age="+student.getAge());
        // 学生 student 调用学生类 Student 方法 show() 打印自己的信息
        // 此处没有给学生 student 属性 sex 赋值,sex 为 null
        student.show();
    }
}

/**
 * 学生类 Student
 * name:属性,学生姓名
 * age:属性,学生年龄
 * sex:属性,学生性别
 * 属性 getter,setter 方法
 * show():方法,打印学生信息
 */
class Student{
    /**
     * 学生姓名
     */
    private String name;

    /**
     * 学生年龄
     */
    private int age;

    /**
     * 学生性别
     */
    private String sex;

    public void setName(String n) {
        name = n;
    }

    public String getName() {
        return name;
    }

    public void setAge(int a) {
        if(a>0&&a<120) {
            age = a;
        }else {
            age = 18;
            System.out.println("年龄无效,默认年龄 18");
        }
    }

    public int getAge() {
        return age;
    }

    public void setSex(String s) {
        sex = s;
    }

    /**
     * 打印学生信息
     */
    public void show() {
        System.out.println("Student [name=" + name + ", age=" + age + ", sex=" + sex + "]");
    }
}

运行结果:

年龄无效,默认年龄 18
name=张三,age=18
Student [name=张三, age=18, sex=null]

getter 和 setter 方法

一般是给**私有属性(private)**才添加 getter 和 setter 方法。

  • getter方法:提供给外部获取属性数据的公共方法;
  • setter方法:提供给外部设置属性数据的公共方法。

格式为:
getter:

[非私有修饰符] 字段类型 getXxx() {
	return 字段名;
}


setter:

[非私有修饰符] void setXxx(字段类型 变量){
	字段=变量;
}

为什么我们要用 getter 和 setter 方法呢?

如果我们把类变量声明为私有的,则一定程度上实现了对数据封装。防止其他程序修改你的变量。通过getter和setter方法能更好的保护你的数据。例如在setter方法中加一些逻辑:上面代码中私有属性 age 的 setter 方法:

    public void setAge(int a) {
        if(a>0&&a<120) {
            age = a;
        }else {
            age = 18;
            System.out.println("年龄无效,默认年龄 18");
        }
    }

这样别人就不知道你具体 setAge 具体怎么写的了。更好的实现数据的封装。

inheritance 继承

继承的概念

继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。

继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
生活中的继承:

在这里插入图片描述
兔子和羊属于食草动物类,狮子和豹属于食肉动物类。

食草动物和食肉动物又是属于动物类。

类的继承格式

在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:

class 父类 {
}
 
class 子类 extends 父类 {
}

为什么需要继承

接下来我们通过实例来说明这个需求。

开发动物类,其中动物分别为企鹅以及老鼠,要求如下:

  • 企鹅:属性(姓名,id),方法(吃,睡,自我介绍)
  • 老鼠:属性(姓名,id),方法(吃,睡,自我介绍)
/**
	企鹅类
*/
public class Penguin { 
    private String name; 
    private int id; 
    public Penguin(String myName, int  myid) { 
        name = myName; 
        id = myid; 
    } 
    public void eat(){ 
        System.out.println(name+"正在吃"); 
    }
    public void sleep(){
        System.out.println(name+"正在睡");
    }
    public void introduction() { 
        System.out.println("大家好!我是" + id + "号" + name + "."); 
    } 
} 
/**
	老鼠类
*/
public class Mouse { 
    private String name; 
    private int id; 
    public Mouse(String myName, int  myid) { 
        name = myName; 
        id = myid; 
    } 
    public void eat(){ 
        System.out.println(name+"正在吃"); 
    }
    public void sleep(){
        System.out.println(name+"正在睡");
    }
    public void introduction() { 
        System.out.println("大家好!我是"+ id + "号" + name + "."); 
    } 
}

从这两段代码可以看出来,代码存在重复了,导致后果就是代码量大且臃肿,而且维护性不高(维护性主要是后期需要修改的时候,就需要修改很多的代码,容易出错),所以要从根本上解决这两段代码的问题,就需要继承,将两段代码中相同的部分提取出来组成 一个父类:

public class Animal { 
    private String name;  
    private int id; 
    public Animal(String myName, int myid) { 
        name = myName; 
        id = myid;
    } 
    public void eat(){ 
        System.out.println(name+"正在吃"); 
    }
    public void sleep(){
        System.out.println(name+"正在睡");
    }
    public void introduction() { 
        System.out.println("大家好!我是" + id + "号" + name + "."); 
    } 
}

这个Animal类就可以作为一个父类,然后企鹅类和老鼠类继承这个类之后,就具有父类当中的属性和方法,子类就不会存在重复的代码,维护性也提高,代码也更加简洁,提高代码的复用性(复用性主要是可以多次使用,不用再多次写同样的代码) 继承之后的代码:

/**
	企鹅类
*/

public class Penguin extends Animal { 
    public Penguin(String myName, int myid) { 
        super(myName, myid); 
    } 
}

/**
	老鼠类
*/
public class Mouse extends Animal { 
    public Mouse(String myName, int myid) { 
        super(myName, myid); 
    } 
}

注意:java不支持多继承,但支持多重继承
在这里插入图片描述

super 与 this 关键字

  • super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。We can use the super keyword to access members of the parent class, which is used to reference the parent class of the current object.

  • this关键字:指向自己的引用。A reference to oneself.
    实例:

class Animal {
  void eat() {
    System.out.println("animal : eat");
  }
}
 
class Dog extends Animal {
  void eat() {
    System.out.println("dog : eat");
  }
  void eatTest() {
    this.eat();   // this 调用自己的方法, 也就是Dog类的
    super.eat();  // super 调用父类方法, 也就是Animal类的
  }
}
 
public class Test {
  public static void main(String[] args) {
    Animal a = new Animal();
    a.eat();
    Dog d = new Dog();
    d.eatTest();
  }
}

输出结果为:

animal : eat
dog : eat
animal : eat

polymorphism and down casting 多态性与下转换

polymorphism 多态

多态是继封装、继承之后,面向对象的第三大特性。

现实意义理解:

  • 现实事物经常会体现出多种形态,如学生,学生是人的一种,则一个具体的同学张三既是学生也是人,即出现两种形态。

  • Java作为面向对象的语言,同样可以描述一个事物的多种形态。如Student类继承了Person类,一个Student的对象便既是Student,又是Person。

概述:

  • 多态体现为父类引用变量可以指向子类对象。
  • 前提条件:必须有子父类关系。
  • 多态的定义与使用格式:
    定义格式:父类类型 变量名=new 子类类型();
  • 理解: 多态是同一个行为具有多个不同表现形式或形态的能力。 多态就是同一个接口,使用不同的实例而执行不同操作。

多态的转型(up casting and down casting)

  • 多态的转型分为向上转型和向下转型两种

  • 向上转型:多态本身就是向上转型过的过程

    使用格式:父类类型 变量名=new 子类类型();

    适用场景:当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作。

  • 向下转型:一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用类型转为子类引用各类型

    使用格式:子类类型 变量名=(子类类型) 父类类型的变量;

    适用场景:当要使用子类特有功能时。

实例:

public class demo {
    public static void main(String[] args) {
        People p=new Stu(); //向上转型
        p.eat(); //打印结果为吃水煮肉片
        //调用特有的方法
        Stu s=(Stu)p; //向下转型
        s.study(); //打印结果为好好学习
       
    }
}
class People{
    public void eat(){
        System.out.println("吃饭");
    }
}
class Stu extends People{
    @Override
    public void eat(){
        System.out.println("吃水煮肉片");
    }
    public void study(){
        System.out.println("好好学习");
    }
}
class Teachers extends People{
    @Override
    public void eat(){
        System.out.println("吃樱桃");
    }
    public void teach(){
        System.out.println("认真授课");
    }
}

exceptions


abstract classes 抽象类

首先用关键字abstract修饰的类成为abstract类,如:

abstract  A{
...
}

注意:对于abstract方法,只允许声明,不允许实现,而且不能使用final和abstract同时修饰一个方法

  • abstract类中可以有abstract方法,也可以有非abstract方法
  • abstract类不能使用new运算创建对象

重点:如果一个非抽象类是某个抽象类的子类,那么它必须重写父类abstract方法,给出方法体。这就是为什么不允许使用final和abstract同时修饰一个方法的原因

  • 如果一个abstract类是abstract类的子类,它可以重写父类的abstract方法,也可以继承这个方法。

实例:

abstract class A
{
	abstract int sum(int x,int y)int sub(int x,int y)
	{
		return x-y;
	}
}
class B extends A
{
	int sum (int x,int y)//子类必须重写父类的sum方法,因为他用abstract修饰
	{
		return x+y;
	}
}
public class C
{
	public static void main(String args[])
	{
		B b=new B();
		int sum=b.sum(30,20);//调用重写的方法
		int sub=b.sub(30,20);//调用继承的方法
		System.out.println("sum="+sum);//输出结果sum=50
		System.out.println("sum="+sum);//输出结果sum=10
	}
}

使用abstract类使我们的程序灵活性更高,后期可维护性更强。Using the abstract class makes our program more flexible and maintainable in the later stages.


interfaces 接口


dynamic dispatch 动态调度


visitor pattern 访问者模式

见:访问者模式


inner classes and anonymous classes 内部类和匿名类

内部类

内部类基本概念:如果A类需要直接访问B类中的成员,而B类又需要建立A类的对象。这时,为了方便设计和访问,直接将A类定义在B类中。就可以了。A类就称为内部类。内部类可以直接访问外部类中的成员。而外部类想要访问内部类,必须要建立内部类的对象。

class Outer {
        int num = 4;
 
        class Inner {
            void show() {
                System.out.println("inner show run " + num);
            }
        }
 
        public void method() {
            Inner in = new Inner();// 创建内部类的对象。
            in.show();// 调用内部类的方法。
        }
    }

为什么内部类可以直接访问外部类中的成员呢?

那是因为内部中都持有一个外部类的引用。这个是引用是 外部类名.this

内部类可以定义在外部类中的成员位置上,也可以定义在外部类中的局部位置上。

当内部类被定义在局部位置上,只能访问局部中被final修饰的局部变量。

匿名内部类

没有名字的内部类。就是内部类的简化形式。一般只用一次就可以用这种形式。匿名内部类其实就是一个匿名子类对象。想要定义匿名内部类:需要前提,内部类必须继承一个类或者实现接口。

匿名内部类的格式:
new 父类名&接口名(){ 定义子类成员或者覆盖父类方法 }.方法

匿名内部类的使用场景:
当函数的参数是接口类型引用时,如果接口中的方法不超过3个。可以通过匿名内部类来完成参数的传递。
其实就是在创建匿名内部类时,该类中的封装的方法不要过多,最好两个或者两个以内。

class Polygon {
   public void display() {
      System.out.println("在 Polygon 类内部");
   }
}

class AnonymousDemo {
   public void createClass() {

      // 创建的匿名类继承了 Polygon 类
      Polygon p1 = new Polygon() {
         public void display() {
            System.out.println("在匿名类内部。");
         }
      };
      p1.display();
   }
}

class Main {
   public static void main(String[] args) {
       AnonymousDemo an = new AnonymousDemo();
       an.createClass();
   }

输出结果为:

在匿名类内部。

initialisers 初始化

Java程序初始化的顺序:

  1. 有继承关系,父类是爸爸;先执行父类,再执行子类
  2. 静态代码块最先执行(只在类加载时执行一次,先父后子,与代码在类种位置无关)
  3. 构造方法(先父后子)
  4. 非静态内容(先父后子,按顺序执行,与代码在类种位置有关)
class Dad{
    static{
        System.out.println("Dad的静态代码块");
    }
    public void fun(){
        System.out.println("Dad的fun方法");
    }
    public Dad(){
        System.out.println("Dad的构造方法");
    }
}

class Son extends Dad{
    static{
        System.out.println("Son的静态代码块");
    }

    public static void main(String[] args){
        Dad dad = new Dad();
        dad.fun();
    }
}

运行结果顺序:

开始运行...

Dad的静态代码块
Son的静态代码块
Dad的构造方法
Dad的fun方法

运行结束。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值