创建与初始化对象
使用new
关键字创建对象
使用new
关键字创建对象的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用。
类中的构造器也称为构造方法,是在创建对象的时候必须要调用的。并且构造器有以下两个特点:
-
必须和类的名字相同
-
必须没有返回类型,也不能写
void
-
this
代表当前类,如this.name, this.age
面向对象编程**(Object Oriented Programming)**的实质是:以类的方式组织代码,以对象的方式封装数据。
类与对象:
- 类是一个模板,抽象性强
- 对象是一个具体的实例,是基于特定模板创建的,个性化明显。对象是通过引用来操作的:栈–>堆
类中的属性,也称为字段field、成员变量
默认的初始化:
- 数字:int 0;float:0.0
- char:\u0000
- boolean:false
- 引用:null
属性的创建:
qualifier修饰符 属性类型 属性名 = 属性值 // 属性类型包括:基本类型(8),引用类型
继承
-
所谓”道生一,一生二,二生万物“,所以尽管我们定义的某一个类是抽象的模板,但是还可以对这些类进一步抽象,产生进一步抽象的类。在java中,有一个终极类 ,叫做
object
,其他类都直接或间接继承这一个类。 -
子类继承父类,使用关键字
child extends Parent()
来表示继承父类的子类。 -
Java中只有单继承,没有多继承。(即只有一个直接父亲,其他的都是祖宗)
super和this的使用
super()、 super.attribute/method
,super
指向当前类继承的父类的实例对象
,而非类对象。this() this.attribute/method
,this可以在任何类中使用。this
指向当前类的实例对象,如this.name, this.age
,相当于python中的self
。- 类的
静态属性
和静态方法
中不能用this
或super
,此时直接用类名
即可。
继承案例代码
package com.benjamin.OOB;
public class Application {
public static void main(String[] args) {
// Student student01 = new Student("Xiaoming", "male");
// Student student02 = new Student("Xiaohong", "female");
//
// student01.setAge(5);
// student02.setAge(6);
//
// System.out.println(student01.getName()+" is a "+student01.getGender()+" child, "+student01.getAge()+" year old.");
// System.out.println(student02.getName()+" is a "+student02.getGender()+" child, "+student02.getAge()+" year old.");
Student student = new Student();
}
}
// =================================Student类=================================
package com.benjamin.OOB;
public class Student extends Person {
// 设定属性私有,通过get/set进行管理访问,这本质上就是"封装"
private String name;
private int age;
private String gender;
// this代表当前这个最直接的对象
// super代表父类(最直接继承的对象)
public Student() {
//super()调用的是父类的构造器(有参无参都可以,要灵活应对)
// super()必须放在子类构造器的“第一行”
// 如果当前类继承了父类,即使在该类的构造器中不显示的写出super(),编译器也会自动为我们加上super()这个声明
super();
// this()是调用本类的构造器(有参无参都可以,要灵活应对)
// 调用this也必须放在该构造器主题内容的第一行;所以不能同时调用super()和this()
//this("zhangsan","male");
System.out.println("Student的无参构造器执行完成");
}
// constructor
public Student(String name,String gender){
this.name = name;
this.gender = gender;
}
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
public int getAge(){
return this.age;
}
public void setAge(int age){
if(age > 120 || age < 0){
age = 3;
System.out.println("Stupid number");
}
else{
this.age = age;
}
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
// =================================Person类====================================
package com.benjamin.OOB;
public class Person {
String name;
int age;
// 使用new本质上是在调用构造器(构造函数/构造方法)
// 构造器用来初始化属性、进行一些操作
// 注意:
// *******必须没有返回类型,但不能写void************
// 构造函数名必须和类名相同
public Person() {
System.out.println("Person的无参构造器执行完成");
}
// 一旦定义了有参构造,无参构造必须显示定义(这是因为当我们一旦开始定义构造函数时,编译器就不再自行定义构造函数了)
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Alt + Insert可以利用IDE提供的快捷方式快速显示定义构造函数
// 构造器(函数)可以有很多个,本是上就是方法重载,由编译器来判断我们想要哪一个
}
方法重写
重写都是子类针对父类的方法
重写需要满足:
- 方法名必须相同;
- 参数列表必须相同
- 修饰符范围可以扩大,但不能缩小
public
>protected
>default
>rivate
- 抛出异常:范围可以缩小,但不能扩大。
重写
是多态
的前提和基础。
多态
一个对象的实际类型是确定的,但是指向实际对象的引用类型有很多,如该类引用
、父类引用
、祖宗引用
都可以指向当前实例对象。
多态注意事项
- 多态是方法的多态,属性没有多态
- 有继承关系,且方法需要
重写
- 多态实例化方法:
Father f1 = new Son();
不能被重写的方法:
static
标识的方法final
修饰的方法private
修饰的方法
代码说明
// ====================================Application类================================================
package com.benjamin.OOB;
import com.benjamin.OOB.Demo02.Person;
import com.benjamin.OOB.Demo02.Student;
public class Application {
public static void main(String[] args) {
// 一个对象的的实际类型是确定的
// 但与之建立的引用类型就不一定是唯一的,该对象的引用类型可以是该类型、父类或祖宗类
Student s1 = new Student();
// 一个对象能执行哪些方法,与定义时左边的引用类型有关,这个引用类型划定了可以使用的属性和方法的范围。
// new Student()时,创建了一个Student对象,这个Student对象的内容包含了其父类Person的方法和属性
// 左边的Person s2 规定了 s2 可以引用的内容仅限 Person 里有的属性和方法(如果有重写的方法,则用子类重写的方法)
// 注意和 Person s2 = new Person() 这种普通方式创建类的区别
// 这就是“多态”
Person s2 = new Student(); // 打印:run==>Student
Object s3 = new Student(); // 打印:run==>Student
s1.run();
s2.run();
System.out.println("================");
System.out.println("s1 "+s1.age); // 打印:s1 5
System.out.println("s2 "+s2.age);// 打印:s2 10
// 这说明多态是方法是多态,属性不存在多态
// 子类在创建对象时,父类属性和子类属性的内容会同时创建,即使同名属性也可以同时存在
System.out.println("================");
// 由于 s2 不能直接利用子类独有的方法,所以必须强制向下类型转换
((Student) s2).eat();
// 打印:
// eating!
// Person's age: 10
}
}
//=============================================以下是Student类==========================================
package com.benjamin.OOB.Demo02;
public class Student extends Person{
public int age = 5;
@Override
public void run() {
System.out.println("run==>Student");
}
public void eat(){
System.out.println("eating!");
System.out.println("Person's age: "+super.age);
}
}
// =============================================以下是Perosn类===========================================
package com.benjamin.OOB.Demo02;
public class Person {
public int age = 10;
public void run(){
System.out.println("run==>Person");
}
}
instanceof 理解
字面理解:判断是否为某一类的实例,返回布尔值
代码里理解:
// ====================================Application类================================================
package com.benjamin.OOB;
import com.benjamin.OOB.Demo02.Person;
import com.benjamin.OOB.Demo02.Student;
import com.benjamin.OOB.Demo02.Teacher;
public class Application {
public static void main(String[] args) {
// 继承关系如下
// Object > String
// Object > Person > Teacher
// Object > Person > Student
Object object = new Student();
// 虽然 Student 类从父子类的角度将在下游,但是从内容的丰富性来讲,越是下游,丰富度越高
// 这也是多态产生的关键原因
// 所以父类类型引用可以指向子类模板实例化产生的对象
// 再来分析具体的问题:
// new Student创建对象之所以能成功,离不开Object类、Person类、Student类的模板化引导
// 所以object引用类型指向的对象可以说都是Student类、Person类、Object类的实例,故为true
// 相反,new Student创建对象和Teacher类、String类没有任何关系
// 所以object引用类型指向的对象不是Teacher类、String类的实例,故为false
System.out.println(object instanceof Student); // true
System.out.println(object instanceof Person); // true
System.out.println(object instanceof Object); // true
System.out.println(object instanceof Teacher); // false
System.out.println(object instanceof String); // false
// 下面的分析思路同理
Person person = new Student();
System.out.println(person instanceof Student); // true
System.out.println(person instanceof Person); // true
System.out.println(person instanceof Object); // true
System.out.println(person instanceof Teacher); // false
//System.out.println(person instanceof String); // false
Student student = new Student();
System.out.println(student instanceof Student); // true
System.out.println(student instanceof Person); // true
System.out.println(student instanceof Object); // true
//System.out.println(student instanceof Teacher); // false
//System.out.println(student instanceof String); // false
}
}
// ======================================以下是Student类=======================================
package com.benjamin.OOB.Demo02;
public class Student extends Person{
public void run(){
System.out.println("=====run=====");
}
}
// ======================================以下是Teacher类=======================================
package com.benjamin.OOB.Demo02;
public class Teacher extends Person{
}
// ======================================以下是Person类=======================================
package com.benjamin.OOB.Demo02;
public class Person {
public void go(){
System.out.println("=====go=====");
}
}
引用类型转换
子类引用类型
转换为父类引用类型
,可以平滑转换,因为子类引用对应的内容圈更大,父类引用对应的内容圈相对较小,以大转小很自然,相当于水自然而然向下流(势能高的原因),代价就是损失一些子类特有的方法和属性。
Parent parent = child; // child是子类引用类型,parent是新定义的父类引用类型。
父类引用类型
转换为子类引用类型
,由于要扩大自己的内容圈,相当于要把水流由低处抽送到高处,这是要费力做工才能实现的,所以要强制转换。
Child child = (child)parent; //和8个基本类型的强制转换 格式一致。在被转换的类型前面加上 (目标引用类型)
static静态理解
static既可以修饰类属性,又可以修饰类方法。由于是固定不变的,所以共用一份就可以。
// =============================Application类=====================================
package com.benjamin.OOB;
import com.benjamin.OOB.Demo02.Person;
import com.benjamin.OOB.Demo02.Student;
import com.benjamin.OOB.Demo02.Teacher;
import com.benjamin.OOB.Demo03.Static;
public class Application {
public static void main(String[] args) {
Static s1 = new Static();
System.out.println("***********************");
Static s2 = new Static();
}
}
// =============================Static类==========================================
package com.benjamin.OOB.Demo03;
public class Static {
{
// 2. 匿名代码块可以赋初值
System.out.println("匿名代码块 anonymity code block");
System.out.println("====================");
}
static{
// 1. static代码块只执行一次
System.out.println("静态代码块 static code f1");
System.out.println("====================");
}
public Static() {
// 3.
System.out.println("构造器代码块 constructor code block");
System.out.println("====================");
}
}
内部类
在类的内部再定义一个类,这个类中类就称为内部类。
抽象类
abstract
修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法
;如果修饰类,那么该类就是抽象类
。抽象类
中可以没有抽象方法
,但是有抽象方法
的类一定要声明为抽象类
。抽象类
不能使用new
关键字来创建对象,它是用来让子类继承的。抽象方法
,只有方法的声明,没有方法的实现,它是用来让子类实现的。- 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。
//=================================Application类====================================
package com.benjamin.OOB;
import com.benjamin.OOB.Demo03.Concrete;
public class Application {
public static void main(String[] args) {
Concrete concrete = new Concrete();
concrete.doSomething();
}
}
// ================================以下是Concrete类========================================
package com.benjamin.OOB.Demo03;
public class Concrete extends Abstract {
public void doSomething(){ // 子类必须实现抽象父类的抽象方法
System.out.println("I've made it come true");
}
}
// =================================以下是Abstract类========================================
package com.benjamin.OOB.Demo03;
public abstract class Abstract {
// abstract, 抽象方法,只有方法的声明,没有方法的实现
public abstract void doSomething();
// 1. 不能new这个抽象类,只能靠子类来实现它
// 2. 抽象类中可以写普通的方法
// 3. 抽象方法必须在抽象类中
// 抽象类存在构造器吗?抽象类的意义是什么?
}
接口
声明类的关键字是class,声明接口的关键字是interface
接口是抽象方法
和常量值
的定义的集合。
- 普通类:只有具体的实现;
- 抽象类:具体实现和规范(抽象方法)都有
- 接口:只有规范!接口内部绝不写实现的具体方法,专业级约束。约束和实现分离:面向接口编程~
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是… , 则必须能…”的思想。
接口的本质是契约,就如同法律一样,制定好后大家都需要遵守。
//==================================接口1定义======================================
package com.benjamin.OOB.Demo04;
public interface UserService { // 用interface标识接口
//java接口中定义的所有方法其实都是抽象方法 public abstract
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
//===================================接口2定义======================================
package com.benjamin.OOB.Demo04;
public interface TimerService {
void timer();
}
//====================================接口抽象方法的具体实现===========================
package com.benjamin.OOB.Demo04;
// 类可以实现接口定义的方法:implements 接口
// 实现接口的类,就需要重写接口中的方法
// 侧面实现了多继承~
public class UserServiceImpl implements UserService,TimerService{
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
@Override
public void timer() {
}
}