一、构造器
1.构造器:constructor,他是类的第三个成员。
2.作用:
(1)和new关键字一起,就可以创建对象。
(2)在创建对象的同时,给对象的实例变量初始化。
3.构造器和方法长得很像,又把构造器称为构造方法。
(1)构造器的名字和类名必须完全一致,包括大小写。
(2)构造器没有返回值,也不写void。
(3)构造器的修饰符只有权限修饰符,没有其他修饰符。
语法格式:
[修饰符] class 类名{
-【权限修饰符】 类名(形参列表){
}
}
4.构造器的其他特点
(1)任何类都有构造器
(2)如果程序员没有编写构造器,那么编译器就会自动无参构造
(3)如果程序员手动编写构造器,那么编译器就不会自动添加无参构造。
(4)一个类可以有多个构造器,他们构成重载。
set:为其中一个变量赋值/修改其中一个变量
get: 获取其中一个变量的值
构造器:创建对象,每次new都是新的对象,在创建对象的同时给成员变量赋值
例子:
public class TestConstructor {
public static void main(String[] args) {
Student stu = new Student();
Scanner input = new Scanner(System.in);
}
}
class Student{
Student(){
//无参构造
}
Student(String name, int age){
//有参构造
}
}
二、继承
1.面向对象的基本特征之一。
2.代码的复用和代码的扩展就会用到复用。
3.语法:
关键字:extends
语法格式:【修饰符】class子类名 extends 父类名{
}
4.继承的特点:
(1)子类中会继承父类所有的成员变量、成员方法等,但是父类中私有的成员变量成员方法等在子类无法直接使用。
(2)子类不会继承父类的构造器
(3)子类虽然不能继承父类的构造器,但是”必须“在子类的的构造器中调用父类的构造器;
默认情况下,子类的构造器中,调用的是父类的无参构造
子类的构造器中可以使用super()调用父类的无参构造;
如果没有写super(),也没写super(实参列表),默认找到父类的无参构造。
如果父类没有无参构造,就必须在子类的构造器中手动调用父类的有参构造: super(实参列表) 该实参列表要与父类被调用的有参构造的形参列表一一对应
(4)java只支持单继承
一个子类只能有一个直接的父类。
(5)父类还可以有父类
(6一个父类支持很多个子类)
举例
public class TestInherited {
public static void main(String[] args) {
//创建Student对象
Student stu = new Student();//使用无参构造
// Student stu2 = new Student("张三",23);//子类没有编写有参构造,不会从父类继承有参构造
stu.setName("张三");
stu.setAge(23);
System.out.println(stu.getInfo());
stu.test();
Student stu2 = new Student("李四",24);
System.out.println(stu2.getInfo());
}
}
class Person{
String name;
private int age;
public Person(String name) {
this.name = name;
}
public Person(String name, int age) {
System.out.println("父类的有参构造");
this.name = name;
this.age = age;
}
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getInfo(){
return "姓名:" + name + ",年龄:" + age;
}
}
//需求:声明一个学生类,教师类
/*
class Student{
private String name;
private int age;
private int score;
//...
}
class Teacher{
private String name;
private int age;
private double salary;
//...
}*/
class Other{
}
//Student是子类,Person是父类
class Student extends Person{
public Student(){
// super("张三",23);//语法正确,就是有点奇怪,把name和age就是初始化为常量值
super();//调用父类的无参构造
}
public Student(String name, int age){
super(name, age);//调用父类的有参构造
}
public void test(){
// System.out.println("name =" + name);
System.out.println("name =" + getName());
}
}
//Teacher是子类,Person是父类
class Teacher extends Person{
public Teacher(String name, int age){
super(name, age);
}
}
三、重写
重载:Overload
重写:Override
1.重写
(1)什么情况下重写?
子类继承父类的方法时,会继承父类的所有方法。
注:父类私有的方法,子类中无法直接使用
子类继承父类的方法之后,觉得父类的方法实现不适合子类,那么子类可以选择对它进行重写
(2)如何重写
1.方法名必须相同
2.形参列表必须相同
(如果形参列表不同就是重载)
3.返回值类型
基本数据类型和void:必须相同
引用数据类型子类<=父类
4.修饰符:
权限修饰符:子类>= 父类
其他修饰符: static 不能重写
(3)当子类重写了父类的某个方法,但是子类中又想要调用这个被重写的方法时,必须加”super.“
class Animal{
protected void eat(){
System.out.println("吃东西");
}
public Animal method(){
return null;//返回空,null可以赋值给任意引用数据类型
}
public static void test(){
System.out.println("父类的静态方法");
}
}
class Dog extends Animal{
public void eat(){
//调用父类的eat()
super.eat();
System.out.println("啃骨头");
}
/* public String eat(){
System.out.println("啃骨头");
return "骨头渣子";
}*/
public Dog method(){
return null;//返回空,null可以赋值给任意引用数据类型
}
public static void test(){
System.out.println("子类的静态方法");
}
}
四、关键字:this和super
1、this:当前对象
(1)在构造器中表示正在new的对象
(2)在成员方法中表示 调用这个方法的对象
2、用法
(1)this.成员变量
在构造器、非静态方法和代码块中,当成员变量与局部变量重名时,在成员变量的前面加this.,重名时不能省略this.
(2)this.成员方法 (非常少)
在非静态方法和代码块中,表示调用当前对象的其他方法,可以加this.,也可以省略
(3)this()或this(实参列表)
位置:只能出现在构造器的首行
表示调用本类的其他构造器
this():表示调用本类的无参构造
this(…):表示调用本类的有参构造
目的是:代码复用
三、找寻顺序和原则 ==> 就近原则和追根溯源原则
1、this()和this(实参列表):只在本类中找对应构造器
2、super()和super(实参列表):只在直接父类找对应构造器
3、在方法中出现对变量的引用,既没有this.变量,又没有super.变量
(1)先看局部变量
(2)如果没有,看本类的成员变量
(3)如果没有,看父类的成员变量,而且这父类不仅限于直接父类,前提条件是可见
(4)如果没有,报错
4、在构造器或方法中出现this.变量
(1)先看本类的成员变量
(2)如果没有,看父类的成员变量,而且这父类不仅限于直接父类,前提条件是可见
(3)如果没有,报错
5、在构造器或方法中出现super.变量
(1)先看直接父类中有没有该成员变量,前提条件是可见
(2)如果没有,去父类的父类中查找,前提条件是可见
6、在构造器或方法中出现对方法的调用,没有加this.方法,也没有加super.方法,也没有 类名.方法,也没有 对象名.方法
(1)先从本类的方法列表中查找
(2)如果没有,看父类,而且这父类不仅限于直接父类,前提条件是可见
7、在构造器或方法中出现this.方法的调用
(1)先从本类的方法列表中查找
(2)如果没有,看父类,而且这父类不仅限于直接父类,前提条件是可见
8、在构造器或方法中出现super.方法的调用
(1)在直接父类中查找该方法,前提条件是可见
(2)如果没有,去父类的父类中查找,前提条件是可见
这里要注意一个问题,super.方法,一旦某个父类中找到,就不会往上追溯了。
public class TestThisSuper {
public static void main(String[] args) {
Employee e1 = new Employee();
Employee e2 = new Employee(1,"张三");
Employee e3 = new Employee(1,"张三","10086","123456");
}
}
class A{
public void method(){
System.out.println("a");
}
}
class B extends A{
public void method(){
System.out.println("b");
}
}
class C extends B{
public void method(){
//访问A类的method方法
super.method();
// super.super.method();//错误,无法直接访问A类的method,因为B类重写了,对于C来说,只能看到B类重写的method
}
}
class Employee{
private int id;
private String name;
private int age;
private String tel;
private String cardId;
private String address;
public Employee() {
System.out.println("一个员工对象创建了");
}
public Employee(int id, String name) {
this();
this.id = id;
this.name = name;
}
public Employee(int id, String name, String tel, String cardId) {
this(id,name);
this.tel = tel;
this.cardId = cardId;
}
public Employee(int id, String name, int age, String tel, String cardId, String address) {
this(id,name,tel,cardId);
this.age = age;
this.address = address;
}
}
class Manager extends Employee{
private double bonus;
public Manager() {
//省略super()
}
public Manager(int id, String name, double bonus) {
super(id, name);//必须在子类构造器首行
this.bonus = bonus;
}
public Manager(int id, String name, String tel, String cardId, double bonus) {
this(id, name,bonus);
this.bonus = bonus;
}
public Manager(int id, String name, int age, String tel, String cardId, String address, double bonus) {
super(id, name, age, tel, cardId, address);
this.bonus = bonus;
}
}
五.成员变量的初始化
1、成员变量是有默认值
byte,short,int,long:0
float,double:0.0
char:\u0000
boolean:false
引用数据类型:null
2、成员变量分为
(1)静态变量:所有对象共享,和类共存亡
(2)实例变量:每一个对象独立的,和对象共存亡
它什么时候初始化?它初始化的方式有哪些?
3、静态变量的初始化方式和时机
(1)静态变量是在类初始化时完成初始化的
我们在使用一个类时,先要把类加载到内存,然后完成类的初始化,才能使用这个类中的方法等
(2)类初始化的过程,其实是在执行一个()方法
中的cl:代表class,init代表:initialize
方法不是程序员收到编写的,而是编译器自动生成的,每一个类都有,也只有一个。
它的代码是由:
①静态变量的显式赋值语句
②静态代码块的语句
按编写的顺序组装而成。
4、静态代码块
作用:为静态变量初始化
因为实际开发中,很少编写 static int a = getNum()这种方式为静态变量赋值,
我们静态变量的值又不是常量值,可能需要读取配置文件来为静态变量初始化,
这个时候就需要一大段代码为静态变量完成赋值,那么我们就可以把这样的代码放在静态代码块中。
public class TestInitialize {
public static void main(String[] args) {
Demo.method();//跨类调用静态方法,使用“类名.”
}
}
class Demo{
static{
System.out.println("静态代码块");
}
static int a = getNum(); //通过调用getNum方法为a静态变量赋值,是为了看到初始化的过程
public static int getNum(){
System.out.println("getNum方法被调用了");
return 10;
}
public static void method(){
System.out.println("静态方法");
}
}