类、对象、引用
类
- 类是具有相同属性和行为的对象的集合。
- 类定义了该类型对象的数据结构, 称之为“成员变量”,同时也定义了一些可以被调用的功能,称之为“方法”。
- 类是用于构建对象的模板,对象的实质就是内存中的一块存储区域,其数据结构由定义它的类来决定。
- 定义类
- 类的成员变量
- 类的成员方法
对象
- 当一个类的定义存在后, 可以使用 new 运算符创建该类的对象。
- 对象创建的过程一般称为类的实例化
- 语法规则:
成员变量的初始化
- 对象创建之后,其成员变量可以按照默认的方式初始化,对象成员具有默认值。
- 成员变量的默认初始化值规则
成员变量类型 | 默认初始值 |
数值类型 byte、short、int、long、float、 |
0 |
boolean类型 | false |
char | 0000 |
引用类型 | null |
成员变量的调用
成员变量的调用,可以根据某个对象的引用找到成员变量,然后使用成员变量
//1.创建一个汽车
Car car = new Car();//创建对象
//2.给汽车属性赋值
car.pinpai="红旗";
car.color="红色";
car.fadongji="红旗发动机";
car.count=5;
成员方法的调用
- 方法的调用必须通过某个对象的引用。
- 当通过么对象的引用调用方法时,方法中涉及的成员变量就是该对象的成员变量。
Person p1 = new Person();
p1.eat("
火锅
");
p1.sayHello();
p1.driver();
引用类型
- 除8种基本数据类型之前,用类名(接口,数组)声明的变量称为引用类型变量,简称引用。
- 引用类型变量中存储的是某个对象在内存中的地址信息。
- 引用的功能在于访问对象。
- 引用类型变量声明语法规则:
JVM内存结构
方法区
- 该区间用于存放类的信息。java程序运行时候,首先会通过类加载器载入类文件的字节码文件,经 过解析后将其装入方法区。类的各种信息都在方法区保存。
栈内存区
- 栈用于存放程序运行过程中的局部变量。
- 引用类型的变量p ,存储在栈内存中。
堆内存区
- jvm会在其内存空间开一个称为“堆”的存储空间,这部分空间用于存储使用new关键字创建的对象。
- 创建了一个Person对象,存储在堆内存中。
方法的重载
- 在java语言中,允许多个方法的名称相同,但参数列表不同,称之为方法的重载(overload)。 编译器在编译时,会根据其参数的不同,绑定到不同的方法。
this
- 在方法中可以通过this关键字表示调用该方法的对象。
- 通常在类中使用this区分成员变量和参数,如果没有歧义,可以省略this。
- 一个类可以创建多个对象(存储于堆中),但方法只有一份(存储于方法区中)。
null
- 引用类型变量用于存放对象的地址,可以给引用类型赋值为null,表示不指向任何对象。
- 如果某个引用类型变量为null的时候,不能访问对象,否则抛出空指针异常。
构造函数
定义构造方法
- 构造方法是在类中定义的方法(每个类都有构造方法):
— 构造方法的名称必须和类名相同.
— 构造方法没有返回值,但也不能写void.
- 在java语言中可以通过构造方法实现对象成员变量初始化。
构造方法重载
- 为了使用方便对一个类定义多个构造方法,这些构造方法彼此参数不同,称为构造方法的重载。
- 创建对象时,java编译器会根据不同的参数,选择不同的构造函数。
类的继承
- extends关键字可以实现类的继承
- 子类(sub class) 可以继承父类(super class)的成员变量及成员方法。同时也可以定义自己的 成员变量和成员方法。
- java语言不支持多继承,一个类只能继承一个父类。 但一个父类可以有多个子类。
package oopday2;
import java.util.Date;
//动物类型:公共的成员变量, 公共的成员方法
// 颜色、生日、性别、脚的数量 叫、吃、跑
//鸡类:飞,
//狗:看门、
//** Java规定一个Java文件只能有一个公开类,并且这个公开类必须和Java文件名相同
public class Animal {// Animal:动物
//公共的成员变量
String color;//颜色
Date birth;//生日
String sex ;//性别
int count;//脚的数量
//公共成员方法
public void sing(String sing){
System.out.println("叫:" + sing);
}
public void eat(String food){
System.out.println("吃:" + food);
}
public void run(){
System.out.println("到处跑");
}
}
/*
Chicken这个类型只有一个成员方法
class Chicken{// Chicken:鸡
public void fly(){
System.out.println("飞....");
}
}*/
//鸡
//继承了Animal中所有成员方法和成员变量,同时有自己独有的fly方法
class Chicken extends Animal{
public void fly(){
System.out.println("飞....");
}
}
//狗
//继承了Animal中所有成员方法和成员变量,同时有自己独有的seeDoor方法
class Dog extends Animal{
public void seeDoor(){
System.out.println("保护家园....");
}
}
向上造型
- 一个子类的对象可以向上造型为父类的类型 Father f = new Sun();
- java编译器编译的时候根据父类型检查调用的成员变量和成员方法是否匹配。
/向上造型:子类对象赋值给父类的引用
Animal dog = new Dog();//
dog.birth = new Date();
dog.color = "黑色";
dog.sex = "男";
dog.count =4;
dog.sing("汪汪汪汪...");
dog.eat("骨头");
dog.run();
//dog.seeDoor();//编译错误:在编译的时候,dog引用是直接按引用的类型Animal使用,Animal没有seeDoor的方法
//在运行的时候,dog引用找到的是对象的实际类型Dog,进行使用,这个时候就有seeDoor方法
//如果一定要调用seeDoor(),这里只能修改dog的引用类型为Dog,即:Dog dog= new Dog();
instanceof关键字
- 对于一个父类的引用类型,可以指向该类的对象也可以指向其任意一个子类型的对象。
- 通过instanceof关键字判断引用指向的对象的实际类型。
- 根据引用指向的实际类型,将引用强制转换为实际类型
//4.创建Animal:动物就是动物,鸡和狗也是动物
Animal a1 = new Animal();
Animal a2 = new Dog();//Dog和Chicken都是Animal的子类
Animal a3 = new Chicken();
//5.类型转换:
//instanceof:用于判断引用对应的对象是否为某种类型,是结果为true,否则结果为false
//a2是动物,但a2本质上市狗,那么a2就不能转换为鸡这个类型
if (a2 instanceof Dog){ // instanceof的运算结果是ture或者false
//a2是Dog,那么就可以把a2转换为Dog,然后赋值给Dog类型的引用
Dog dog1= (Dog) a2;
dog1.seeDoor();//类型转换之后,就可以调用到子类Dog的所有方法
}
if (a3 instanceof Chicken){
Chicken chicken = (Chicken) a3;
chicken.fly();
}
//Chicken chicken = (Chicken) a2;//这里没有编译错误,有运行错误:ClassCastException - 类型转换错误
/*Exception in thread "main" java.lang.ClassCastException: oopday2.Dog cannot be cast to oopday2.Chicken
at oopday2.TestAnimal.main(TestAnimal.java:58)*/
}
继承中的构造方法
- 子类的构造方法中必须通过super调用父类的构造方法。因为创建子类之前,必须先创建父类。
- 子类的构造函数如果没有直接使用super调用父类构造方法,java编译器会自动的加入对父类无参构造函数的调用(那么要求父类必须有无参构造方法)。
package oopday2;
//图形
public class Shape {//Shape父类
int x;
int y;
public Shape(){//无参数构造函数
System.out.println("Shape的无参构造函数被调用");
}
public Shape(int x,int y){
this.x=x;
this.y=y;
System.out.println("Shape的有参构造函数被调用");
}
//成员函数
public double area(){
System.out.println("Shape的area函数被调用");
return 0;
}
}
class Rect extends Shape{//Rect:子类
double w;
double h;
public Rect(){
super();//调用父亲的无参构造函数,如果要写只能写在构造器函数内部的第一行
//super(); -- 构造器函数内部,会调用父亲型的构造函数,如果没有写super();那么编译器会自动加上super()
System.out.println("Rect的无参构造函数被调用了");
}
public Rect(int x,int y){
super(x,y);//这里表示调用父亲类型的有两个参数的构造器函数
System.out.println("Rect的两个有参构造函数被调用了");
}
public Rect(int x,int y,double w,double h){
//第一行就隐藏了super()
this.x=x;
this.y=y;//this.x=x; this.y=y; 这两句可以简化为super(s,y)
this.w=w;
this.h=h;
System.out.println("Rect的四个有参构造函数被调用了");
}
public Rect(double w,double h){
//super(w,h);//编译错误:super调用父类