Java基础加强重温_01: 基础回顾(类、对象、类成分、封装、构造方法、this关键字)、static关键字(修饰成员变量,成员方法)、继承( )、抽象类(abstract)、模板设计模式

一、IDAE创建projrct

java:有默认model
Empty project:没有默认model

二、基础回顾

1、什么是类和对象?

类:对同一类事物的抽象(简化、概括…)描述。
对象:类的具体某个实例。 对象==实例

举例:

桌子:是一个类,这个桌子:是一个对象/实例
猫:是一个类,Tom猫:是一个实例

2、怎么定义类?

public class 类名(首字母大写,遵循驼峰标识) 如:ApplePen

一个java文件可以定义几个类?

  • 无数个class,但是public修饰的类只能有一个,并且与文件名一致。
  • 开发中一般一个java文件定义一个类
代码示例
public class Demo01 {
    public static void main(String[] args) {
                //0x001
        Student student = new Student("乔碧萝殿下",19,"盛世美颜下的直播");

        //获取名字
        String name = student.getName();
        System.out.println(name);
    }
}

//java文件中定义多个类
//在教学情况下用的多,实际工作中基本不用,一个类一个文件
class Dog {

}

class Cat {

}

3、类中的成分

public class 类名 {
           //1、成员变量(属性、实例变量、类变量...)
           //2、成员方法(行为、函数、实例方法、类方法...)
           //3、构造方法(构造器、构造函数、解析函数...)

           //未来学的
           //4、内部类
           //5、代码块
       }

4、封装

封装是面向对象三大特性之一。(三大特性:抽象、继承、多态)

封装步骤:

  • 1、把成员变量私有化 (使用 private 关键字来修饰成员变量。)
  • 2、提供getter/setter (使用 public 修饰getter和setter方法。)

封装的作用:

  • 1、对于一些私隐可以控制设置和开放
  • 2、可提供代码的逻辑检验(在getter/setter方法中写检验代码)
  • 3、拓展:可以封装方法(组件化)

封装一句话总结:合理隐藏、合理开放

面向对象和面向过程的区别

面向过程:重头到位实现做饭的过程

  • 1、米(自己去耕田收割)
  • 2、洗米(水龙头怎么接水)
  • 3、煮饭(做电饭煲)
  • 4、盛饭(做碗)

面向对象:只关注结果,不关注实现过程

  • 1、妈妈.public 买米(private 走去市场、private 讨价还价、private 给钱、private 背回来)
  • 2、妈妈.洗米
  • 3、饭煲.做饭
  • 4、自己.盛饭

理解:面向对象即封装方法(或说封装过程),调用方法实现结果,不关注过程,只关注结果

5、构造方法

构造方法的作用:
jvm创建对象,构造方法初始化对象(变量初始化)

 类名 变量  = new 类名(参数...);

new 类名(参数…), 分两步解析
new: jvm看到new关键字,在堆内存开辟空间,创建对象
类名(参数…): 即构造方法,执行构造方法初始化对象,(无参构造:用系统默认值初始化。有参构造:用传入的参数出初始化)

6、this关键字

this代表所在类的当前对象的引用(地址值),即代表当前对象。

构造方法的this,指的是对象本身,谁调用方法this就是谁

1、Student类的对象student调用getNmae()方法

   Student student = new Student("乔碧萝殿下",19,"盛世美颜下的直播");
   //获取名字,
   String name = student.getName();

2、在getName()中,加上this,正常返回(一般getter方法,不用加this。)。这个this就是指对像student(谁调用方法this就是谁

public class Student {
//  创建一个学生类,有姓名、年龄、爱好
    private String name;
    private int age;
    private String hobby;

    //默认情况下,系统会赠送一个无参的构造方法
    public Student(){

    }

    //右键->generate->contructor->选中变量->ok
    public Student(String name, int age, String hobby) {
        this.name = name;
        this.age = age;
        this.hobby = hobby;
    }

	
    public String getName() {
        return this.name; //测试加上this。正常返回
    }
    
	public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;  //正常getter方法,不用加this。
    }
    ...
this关键字的应用
  • 1、用于普通的gettter与setter方法

  • 2、用于构造器中
    构造器即构造方法

三、static关键字

static是静态的意思。 static可以修饰成员变量或者修饰方法。
static修饰的变量,只在第一次代码执行的时候初始化。例如你在方法中定义了一个static变量,此时此static变量在第一次调用方法的时候初始化一次,以后调用将不会被初始化。所以,static修饰的变量必须在定义的时候就要给初始值

1、static修饰成员变量 (静态成员变量)

被static修饰的成员是属于类的是放在静态区中,所有的对象【共享】该变量。这个成员变量叫静态成员变量
没有static修饰的成员变量和方法则是属于每个对象的,每个对象都独有的一份。这个成员变量叫实例成员变量

定义格式:

修饰符 static 数据类型 变量名 = 初始值;  
两种成员变量访问对比

静态成员变量的访问

对象.static修饰的成员变量 = xxx;(idea不推荐)
类名.static修饰的成员变量(静态变量) = xxx;

实例变量的访问

对象.实例成员变量

2、static修饰成员方法 (静态成员方法)

有static修饰成员方法,说明这个成员方法是属于类的,这个成员方法称为类方法或者静态方法。
因为类只有一个,所以静态方法在内存区域中也只存在一份,所有的对象都可以共享这个方法。与静态成员变量一样,静态方法也是直接通过类名.方法名称即可访问。

无static修饰的成员方法属于每个对象的, 这个成员方法叫实例方法。
需要注意的是:实例方法是属于每个对象,必须创建类的对象才可以访问。

两种成员变量访问对比

静态成员方法访问

类名.方法名称

实例成员方法访问

对象.实例方法

3、小结:

1.当 static 修饰成员变量或者成员方法时,该变量称为静态变量,该方法称为静态方法。该类的每个对象都共享同一个类的静态变量和静态方法。任何对象都可以更改该静态变量的值或者访问静态方法。但是不推荐这种方式去访问。因为静态变量或者静态方法直接通过类名访问即可,完全没有必要用对象去访问。

2.无static修饰的成员变量或者成员方法,称为实例变量,实例方法,实例变量和实例方法必须创建类的对象,然后通过对象来访问。

3.static修饰的成员属于类,会存储在静态区,是随着类的加载而加载的,且只加载一次,所以只有一份,节省内存。存储于一块固定的内存区域(静态区),所以,可以直接被类名调用。它优先于对象存在,所以,可以被所有对象共享。

4.无static修饰的成员,是属于对象,对象有多少个,他们就会出现多少份。所以必须由对象调用

5、static表示的是静态,此类方法中不能有动态的变量,这样定义的原因是程序运行初始化后,会直接将静态块和变量直接加载到内存,之后不允许动态的修改参数名称或者是方法名称。

四、继承

就是子类继承父类的属性和行为,使得子类对象可以直接具有与父类相同的属性、相同的行为。子类可以直接
访问父类中的非私有的属性和行为。

理解:继承后,父类中的成员变量和成员方法也有,在子类中不写出来,访问时可以当写出来访问。

继承好处:
  1. 子类会拥有父类的属性和行为,提高代码的复用性(减少代码冗余,相同代码重复利用)。
  2. 使类与类之间产生了关系,共同的代码都写在了父类,只需要修改父类就可以应用所有子类,提高代码拓展性。

1、继承的格式

通过 extends 关键字,可以声明一个子类继承另外一个父类

class 父类 {
...
}

class 子类 extends 父类 {
...
}
特点:

1、Java是单继承的,一个类只能继承一个直接父类。

 // 一个类只能有一个父类,不可以有多个父类。
 class A {}
 class B {}
 class C extends A {} // ok
 // class C extends A, B {} // error

2、一个类可以有多个子类。

// A可以有多个子类
 class A {}
 class C1 extends A {}
 class C2 extends  A {}

3、可以多层继承。

 class A {}
 
 class B extends A {}
 
 class C extends B {}

Object类是所有类的父类: 顶层父类是Object类。所有的类默认继承Object,作为父类。

继承练习案例

请使用继承定义以下类:

  1. 学生类 属性:姓名,年龄 行为:吃饭,睡觉
  2. 老师类 属性:姓名,年龄,薪水 行为:吃饭,睡觉,教书
  3. 班主任 属性:姓名,年龄,薪水 行为:吃饭,睡觉,管理

案例分析
老师类,学生类,还有班主任类,实际上都是属于人类的,我们可以定义一个人类,把他们相同的属性和行为都定义。在人类中,然后继承人类即可,子类特有的属性和行为就定义在子类中了。

代码实现:

父类Human类

public class Human {
  // 合理隐藏
  private String name ;
  private int age ;
  // 合理暴露
  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;
 }
}

子类Teacher类

public class Teacher extends Human {
  // 工资
  private double salary ;
 
  // 特有方法
  public void teach(){
    System.out.println("老师在认真教技术!")}
 
   public double getSalary() {
    return salary;
 }
  public void setSalary(double salary) {
    this.salary = salary;
 }
}

子类Student类

public class Student extends Human{
}

子类BanZhuren类

public class Teacher extends Human {
  // 工资
  private double salary ;
 
   // 特有方法
  public void admin(){
    System.out.println("班主任强调纪律问题!")}
 
  public double getSalary() {
    return salary;
 }
  public void setSalary(double salary) {
    this.salary = salary;
 }
}

测试类

public class Test {
   public static void main(String[] args) {
     Teacher dlei = new Teacher();
     dlei.setName("播仔");
     dlei.setAge("31");
     dlei.setSalary(1000.99);
     System.out.println(dlei.getName());
     System.out.println(dlei.getAge());
     System.out.println(dlei.getSalary());
     dlei.teach();
    
     BanZhuRen linTao = new BanZhuRen();
     linTao.setName("灵涛");
     linTao.setAge("28");     linTao.setSalary(1000.99);
     System.out.println(linTao.getName());
     System.out.println(linTao.getAge());
     System.out.println(linTao.getSalary());
     linTao.admin();
     Student xugan = new Student();
     xugan.setName("播仔");
     xugan.setAge("31");
     //xugan.setSalary(1000.99); // xugan没有薪水属性,报错!
     System.out.println(xugan.getName());
     System.out.println(xugan.getAge());
  }
}

2、子类不能继承的内容

1、父类私有(private)的属性和行为能被子类继承(储存),但无法被子类【使用】

子类可以继承父类的私有成员(成员变量,方法),只是子类无法直接访问而已。
父类的private修饰的成员变量,子类可以通过getter/setter方法访问。

2、构造方法:子类不能继承父类的构造器,因为子类有自己的构造器。因为构造方法必须与类名一致,父类的不可能与子类一致,所以不能被继承

拓展:
3、父类静态的方法和变量也可以被继承

3、 继承后构造器的特点,this和super引用构造方法:this()和super()

当类之间产生了子父关系,其中类之间的构造器产生的影响:

构造器的定义格式和作用。

  1. 因为类的构造器名字必须与类名一致(大小一致)。所以子类是无法继承父类构造方法的(因为类名不一致)。
  2. 构造器的作用是初始化对象成员变量数据的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个 super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。(先有爸爸,才能有儿子)继承后子类构造器特点:子类所有构造器的第一行都会先调用父类的无参构造器,再执行自己

super()

每个子类构造方法默认都隐藏了一句话:super(),该方法指的是父类的构造方法

public class Person {
	...
}
public class Student extends Person{
	...
	public Student(){
	//  super();  //父类的构造方法
        System.out.println("儿子的构造方法");
    }
    ...
}

当一个子类对象被创建的时候,首先会在内存中创建一个父类对象,然后在父类对象的外部放上子类独有的属性,这个两者结合起来形成了一个子类的对象。子类是拥有父类的私有属性和方法,但无法直接使用。
super()调用的时父类无参构造方法,super(参数…) 输入参数后调用的是父类有参构造方法

运行原理

父类空间优先于子类对象产生
在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类空
间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。代码体现在子类的构造器调用时,一定先调用父类的构造器。
在这里插入图片描述

this()

this()指的是子类的构造方法,可以理解为本类的构造方法
在子类有参构造方法调用子类无参构造,在new子类对象时执行有参构造和无参构造

public class Student extends Person{
	...
	public Student(){
        System.out.println("儿子的构造方法");
    }

	public Student(String name,int age){
		this(); //添加this()
        System.out.println("儿子的构造方法");
    }
    ...
}
注意

1、this()与super(): this(),super()必须要放在第一句

  • 对于父类非私有的变量,super存在的价值是:解决子类无法通过this/super直接访问父类的私有变量,设计者为了统一,父类的变量初始化统一放到了父类构造方法中
  • super()为什么要放第一句:如果不是第一句意味着可以this/super去调用父类的变量,而这个时候父类的变量还没初始化。

2、this()和super()不能共存,否则编译异常,只能选择其中之一。本质第一句永远都是super(参数…)

小结:

this和super三大作用:调用属性、调用方法、利用this表示当前对象。

//调用属性
this.成员变量  --   本类的
super.成员变量  --   父类的

//调用方法
this.成员方法名() --   本类的  
super.成员方法名()  --   父类的

//指代构造方法
super(...) -- 调用父类的构造器,根据参数匹配确认有参/无参
this(...) -- 调用本类的其他构造器,根据参数匹配确认有参/无参
this()与super()使用详解:https://blog.csdn.net/lncsdn_123/article/details/79025525

4、继承后子类成员变量和成员方法的特点

成员变量

1、子类、父类成员变量不重名:

  • 正常访问是没有影响

2、子类、父类成员变量重名

  • 子类会优先访问自己对象中的成员变量。此时想访问父类成员变量需要使用super关键字。super代表的是父类对象的引用,this代表的是当前对象的引用。
super.父类成员变量名

成员方法

1、成员方法不重名:

  • 访问没有影响
    对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。

2、成员方法重名:

  • 创建子类对象调用该方法的时候,子类对象会优先调用自己的方法。
this和super的区别

this 能获取本类、父类有权限的属性和行为,能用在任意类中
super 只能调用父类的有权限的属性和行为,super只能用在子类中

理解:子类继承父类有权限的属性和行为,这些权限和行为等于子类的权限和行为,在本类用this获取当然可以

5、方法重写

子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也
称为重写或者复写。声明不变,重新实现。

区分:
方法重载: 同一个类中相同方法名,不同参数类型(两同一不同)

继承的情况下:子类定义与父类同名的方法
1、同名同参同返回值:

  • 方法重写,不会报错

2、同名同参不同返回值:

  • 报错(二义性问题)
  • 二义性:同名同参的方法在一个类中出现了多个

3、同名同返回值不同参:不报错,等于方法重载

理解:子类继承了父类方法,又在子类定义跟父类同名不同返回值的方法,等于一个类定义两个相同名字不同返回值的方法,因此产生二义性,不知道执行哪个。

应用场景:

认为父类的方法不能满足子类使用,可以进行方法重写。

方法重写案例

定义了一个动物类

public class Animal {
  public void run(){
    System.out.println("动物跑的很快!");
 }
  public void cry(){
    System.out.println("动物都可以叫~~~");
 }
}

定义一个猫类,猫认为父类cry()方法不能满足自己的需求

public class Cat extends Animal {
  public void cry(){
    System.out.println("我们一起学猫叫,喵喵喵!喵的非常好听!");
 }
}

测试

public class Test {
public static void main(String[] args) {
  // 创建子类对象
  Cat ddm = new Cat()// 调用父类继承而来的方法
  ddm.run();
  // 调用子类重写的方法
  ddm.cry();
}
方法重写注意事项
  1. 方法重写是发生在子父类之间的关系。
  2. 子类方法覆盖父类方法,必须要保证权限大于>=父类权限。
  3. 子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样。
  4. 父类private修饰的方法无法被重写
    public > protected > 缺省

@Override重写注解

  • @Override:注解,重写注解校验!
  • 这个注解标记的方法,就说明这个方法必须是重写父类的方法,否则编译阶段报错。
  • 建议重写都加上这个注解,一方面可以提高代码的可读性,一方面可以防止重写出错!
public class Cat extends Animal {
	@Override
	public void cry(){
		System.out.println("我们一起学猫叫,喵喵喵!喵的非常好听!");
	}
}

五、抽象类

父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。父类的方法声明和方法主体,只有声明还有意义,而方法主体则没有存在的意义了(因为子类对象会调用自己重写的方法)。

换句话说,父类可能知道子类应该有哪个功能,但是功能具体怎么实现父类是不清楚的(由子类自己决定),父类完全只需要提供一个没有方法体的方法签名即可,具体实现交给子类自己去实现。

我们把没有方法体的方法称为抽象方法。Java语法规定,包含抽象方法的类就是抽象类。

  • 抽象方法 : 没有方法体的方法。
  • 抽象类: 包含抽象方法的类。
abstract关键字

abstract是抽象的意思,用于修饰方法方法和类。abstract修饰的方法是抽象方法,abstract修饰的类是抽象类。

1、abstract修饰类-抽象类

如果一个类包含抽象方法,那么该类必须是抽象类。注意:抽象类不一定有抽象方法,但是有抽象方法的类必须定义成抽象类。

//抽象类定义格式
abstract class 类名字 {
}

代码举例:

public abstract class Animal {
  public abstract void run()}

抽象类存在的意义是为了被子类继承,否则抽象类将毫无意义。抽象类体现的是模板思想,模板就是通用的东西。抽象类已经是具体的实现(抽象类中可以有成员变量和实现方法),而将模板中不能决定的东西定义成抽象方法,让使用模板(继承抽象类的类)的类去重写抽象方法实现需求,这是典型的模板思想。

抽象类和普通类的区别:

  • 1、抽象类能定义抽象方法,普通类不允许定义抽象方法(如果普通类有抽象方法也变成抽象类)
  • 2、抽象类不能创建对象,普通类可以创建对象。
    没有方法体的抽象方法是不能被调用的,而抽象类中可以定义抽象方法,如果可以创建对象,就可以调用没有方法体的抽象方法。
小结:

抽象类的特征总结起来可以说是 有得有失
有得:抽象类得到了拥有抽象方法的能力。
有失:抽象类失去了创建对象的能力。
其他成员(构造器,实例方法,静态方法等)抽象类都是具备的。

2、abstract修饰方法-抽象方法

使用 abstract 关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体。

//抽象方法定义格式
修饰符 abstract 返回值类型 方法名 (参数列表)

代码举例:

public abstract void run()

特点:

  • 1、必须要被子类重写,体现的是约束作用(约束子类必须重写父类全部的抽象方法)
    子类不重写全部的抽象方法?子类如果不全部重写父类的抽象方法,那子类依然是抽象类
  • 2、抽象方法必须在抽象类内

抽象方法与普通方法的区别:
1、普通方法必须要有方法体,抽象必须没有方法体。(没有方法体即没有{})
2、普通方法结尾不需要加;,抽象方法必须结尾加; (理解:把 {}换成;)

//普通方法
public void work() {
}

//抽象方法
public void work();

定义抽象方法时,不能和哪些关键字共存:

- 1、private

私有的方法无法被子类重写,abstract的方法必须要被子类重写才有意义

- 2、static

静态的方法属于当前类,类.静态方法,abstract的方法没有方法体,不能直接调用

- 3、final

final是最终的意思。final修饰的类不能被继承。同理,被修饰的方法也不能进行修改。 一句话概述:final修饰的东西不能被修改,不能被继承。abstract的意义是为了让子类实现方法而存在,而final的意义是不让子类进行修改,它们是处于一个互斥的意义。当二者同时修饰于一种东西(无论是类,还是方法)上,则会报错

3、总结

关于抽象类的使用,以下为语法上要注意的细节,虽然条目较多,但若理解了抽象的本质,无需死记硬背。

  1. 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
    理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
  2. 抽象类中,可以有构造器,是供子类创建对象时,初始化父类成员使用的。
    理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。
  3. 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
    理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设
    计。
  4. 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则子类也必须定义成抽象类,编译无法通过而报错。
    理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意
    义。
  5. 抽象类存在的意义是为了被子类继承,抽象类体现的是模板思想。
    理解:抽象类中已经实现的是模板中确定的成员,抽象类不确定如何实现的定义成抽象方法,交给具体的
    子类去实现。

六、抽象类的应用——模板设计模式

设计模式
java一共有23种设计模式,设计模式其实就是开发的套路。
什么是模板
做月饼 先做一个模子,丢进去的做月饼的材料是能变的。把固定的东西确定下来,变化的东西根据实际情况修改就是模板。

我们现在使用抽象类设计一个模板模式的应用,例如在小学的时候,我们经常写作文,通常都是有模板可以套用的。假如我现在需要定义新司机和老司机类,新司机和老司机都有开车功能,开车的步骤都一样,只是驾驶时的姿势有点不同, 新司机:开门,点火,双手紧握方向盘,刹车,熄火 , 老司机:开门,点火,右手握方向盘左手抽烟,刹车,熄火 。我们可以将固定流程写到父类中,不同的地方就定义成抽象方法,让不同的子类去重写。

代码实现

司机开车的模板类

public abstract class Driver {
  public void go() {
    System.out.println("开门");
    System.out.println("点火");
    // 开车姿势不确定?定义为抽象方法
    ziShi();
    System.out.println("刹车");
    System.out.println("熄火");
 }
  public abstract void ziShi();
}

定义两个使用模板的司机

public class NewDriver extends Driver {
  @Override
  public void ziShi() {
    System.out.println("新司机双手紧握方向盘");
 }
}
public class OldDriver extends Driver {
  @Override
  public void ziShi() {
    System.out.println("老司机右手握方向盘左手抽烟...");
 }
}

测试类

public class Demo02 {
  public static void main(String[] args) {
    NewDriver nd = new NewDriver();
    nd.go();
    OldDriver od = new OldDriver();
    od.go();
 }
}

运行效果:

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值