一.类和对象
1.类
类是数据以及对数据的一组操作的封装体。
类声明的格式:
类声明
{
成员变量的声明;
成员方法的声明及实现;
}
1.1 声明类
[修饰符] class 类<泛型> [extends 父类] [implements 接口列表]
<泛型>——类的参数,带有参数的类成为泛型类。
1.2 声明成员变量和成员方法
成员变量声明格式:[修饰符] 数据类型 变量[=表达式]{,变量[=表达式]};
成员方法——用来描述对成员变量进行的操作,格式:[修饰符] 返回值类型 方法([参数列表])[throws 异常类]
{
语句序列;
[return [返回值]];
}
例如:
public class MyDate //类声明
{
int year,month,day; //声明成员变量
void set(int y,int m,int d) //成员方法,设置日期值
{ //无返回值,有三个参数
year=y;
month=m;
day=d;
}
}
2.对象
类本身不参与程序运行,实际参与运行的是类的对象。
对象是类的实例(instance),即类的取值。类的一个对象能够获得并保存类的一个实例。
类比:类——对象——类的实例
数据类型———变量——取值
例如:int类型——变量i——取值10
2.1 MyDate d=new MyDate();//声明对象,创建实例并赋值
2.2 引用对象的成员变量和调用成员方法
对象.成员变量
对象.成员方法([参数列表])
注:Java的内存自动管理机制,能够跟踪存储单元的使用情况,自动回收不再被使用的资源,所以,程序中不需要释放对象占用的空间资源。
Java的类是引用数据类型,两个对象之间的赋值是引用赋值,对象赋值过程中没有创建新的实例。
(注:1、“==”作用在引用数据类型间,判断内存地址是否相等,想判断内容实体用equals;
2、基本传值传参传的是副本,修改后原值不变;引用传值传参穿的是地址,修改后原值改变。
引用类型 就是只变量中存储的不是值而是一个内存中的地址的数据类型
也就是说 变量中存储了这个变量的值所在内存中的地址 每次调用这个变量都是引用这个地址而得到真正的值 所以叫引用类型 。
通俗说,将变量名与变量值分开,比如Student s=new Student(),s就是个引用类型的变量,s这个名分配在栈空间里,但是s它指向的值在堆空间里)
二、类的封装性
1.构造方法
用于创建类的一个实例并对实例的成员变量进行初始化。构造方法与类同名;构造方法通过new运算符调用。
构造方法和成员方法的不同之处:
A.作用不同:成员方法实现对类中成员变量的操作;构造方法用于创建类的实例并对实例的成员变量进行初始化。
B.调用方式不同:成员方法通过对象调用;构造方法通过new运算符调用。
例如:
public class MyDate
{
public MyDate (int y,int m,int d)
{
year=y;month=m;day=d;
}
}
使用new运算符调用自定义的构造方法,参数必须符合构造方法的声明。
MyDate d=new MyDate(2009,7,18);//创建实例并初始化成员变量
拷贝构造方法
一个类的构造方法,如果其参数是该类对象,称为拷贝构造方法,它将创建的新对象初始化为形式参数的实例值,实现对象复制功能。
Java不提供默认拷贝构造方法。
public class MyJava {
public static void main(String[] args) {
// TODO 自动生成的方法存根
MyJava d1=new MyJava(2016,4,27);
MyJava d2=new MyJava(d1);
System.out.print(d2.year);
}
private int year;
private int month;
private int day;
public MyJava(int y,int m,int d){
year = y;
month=m;
day=d;
}
public MyJava(MyJava d){
year = d.year;
month=d.month;
day=d.day;
}
输出:2016
2.this引用和instanceof 对象运算符
2.1 this引用
(1)指代对象本身 this
this用于指代调用成员方法的当前对象自身。
(2)访问本类的成员变量和成员方法
this.成员变量
this.成员方法([参数列表])
public MyDate(int year,int month,int day)
{ //指定参数的构造方法,参数与成员变量同名
this.year=year;//this.year指定当前对象的成员变量,year指参数
this.month=month;//this引用不能省略
this.day=day;
}
public MyDate() //默认构造方法,重载
{
this(1970,1,1);//调用本类已定义好的构造方法
}
public MyDate(MyDate d)
{
this(d.year,d.month,d.day);
}
2.2 instanceof 对象运算符
判断一个对象是否属于指定类及其子类,返回boolean类型。
例:MyDate d=new MyDate();
d instanceof MyDate
//返回true,d是MyDate类的实例
3 访问控制
3.1 类的访问控制权限
声明一个类可使用的权限修饰符只有两种: public 和 缺省
共有权限public,可被所有类访问
缺省权限无修饰符,可被当前包(当前文件夹)中的类访问。
一个源程序文件中可声明多个类,但用public修饰的类只能有一个,且该雷鸣必须与文件名相同。
源程序文件MyDate.java中可声明多个类如下:
public class MyDate //公有权限的类
class MyDate_ex //缺省权限的类
类的成员有4种访问控制权限
private—声明私有成员,该成员仅能被当前类的成员访问。(当前类)
缺省—没有修饰符表示缺省权限,说明该成员能被当前类以及当前包中的其他类访问,也称在当前包中可见。(当前包)
protected—声明保护成员,该成员能被当前类及其子类、或当前包中的其他类访问,也称在子类中可见。(子类)
public——声明公有成员,该成员可被所有类访问。(所有)
声明set()和get()方法存取对象的属性 —值对象的某个特性或特征
Java约定,存取对象属性的方法分别是set()和get()。
public void set(int y,int m,int day)//设日期
public void set(MyDate d)//设置日期,重载
public int getYear()//获取年份
4 静态成员
实例成员—属于对象,包括实例成员变量和成员方法。只有创建了实例,才能通过对象访问实例成员变量和实例成员方法。
静态成员—属于类,需要用关键字static标识。包括类成员变量和类成员方法。即使没有创建实例,也可以通过类名直接访问类静态成员变量和调用静态成员方法。
5 析构方法
——用于释放实例并执行特定操作。
public void finalize() //约定析构方法名为finalize
{ //finalize()没有参数,也没有返回值
语句序列;
} //一个类只能有一个finalize()方法,qiefinalize()不允重载
Java的内存自动管理机制能够释放不再将被使用的对象,所以,通常类不需要设计析构方法。
如果需要在释放对象时执行特定操作,则类可以声明析构方法。
注:A.当对象超出它的作用域时,Java将执行对象的析构方法。
B.一个对象也可以调用析构方法来释放对象自己。
C.不能使用已被析构方法释放的对象,否则将产生运行错误。
例如:d.finalize(); //调用对象的析构方法
6 浅拷贝与深拷贝
浅拷贝—一个类的拷贝构造方法,使用一个已知实例对新创建实例的成员变量逐个赋值,这种方法称为浅拷贝。
当对象的成员变量是基本数据类型时,两个对象的成员变量已有存储空间,赋值运算传递值,所以浅拷贝能够赋值实例。
当对象的成员变量是引用数据类型时,浅拷贝不能实现对象复制功能,需要深拷贝。
public class Person
{
String name; //姓名
MyDate birthday; //生日
public Person(String name,MyDate birthday) //构造方法
{
this.name=name;
this.birthday=birthday; //引用赋值
}
public Person(Person p) //拷贝构造方法,复制对象
{
this(p.name,p.birthday);
}
}
深拷贝—当一个类包含引用类型的成员变量时,该类的拷贝构造方法,不仅要复制对象的所有非引用成员变量值,还要为引用类型的成员变量创建新的实例,并初始化为形式参数实例值,这种复制方法称为深拷贝。
三 类的继承
1 由继承派生类
继承:根据一个已知的类由继承方式创建一个类,使新创建的类自动拥有被继承类的全部成员。
父类/超类——被继承类;子类/派生类——通过继承产生的新类
父类和子类的关系:
A.子类自动拥有父类的全部成员,包括成员变量和方法等,使父类成员得以传承和延续;
B.子类可以更改从父类继承来的成员,使父类成员适应新的需求;
C.子类也可以增加自己的成员,使类的功能得以扩充。
D.子类不能删除父类的成员。
声明继承类:[修饰符] class <泛型>[extends 父类] [implements 接口列表]
注:Java的类是单继承的,一个类只能有一个父类,不能有多个父类。
1.1 继承原则
(1)子类继承父类的成员变量
(2)子类继承父类除构造方法以外的成员方法
(3)子类不能继承父类的构造方法
子类没有继承父类的构造方法,因为父类的构造方法只能创建父类实例并初始化,无法创建实例。
例如:父类声明构造方法Person(String,MyDate),当子类没有生命Student(String,MyDate)构造方法时,下列语句是错误的:
Student s1=new Student("李小明",new MyDate(1979,3,15));//语法错,构造方法参数不匹配
(4)子类可以增加成员,可以重定义从父类继承来的成员,但不能删除。
1.2 子类的构造方法
子类对象包含从其父类继承来的成员变量,以及子类声明的成员变量,子类构造方法必须对这些成员变量进行初始化。而父类构造方法已对父类声明的成员变量进行了初始化,因此,子类构造方法必须调用父类的某一个构造方法。
1.2.1 使用super()调用父类构造方法
在子类的构造方法体中,可以使用"super引用"调用父类的构造方法。其语法如下:
super([参数列表])
public Student(String name,MyDate birthday,String spec)
{
super(name,birthday); //super()调用必须是第一条语句 调用父类同参数的构造方法
this.speciality=spec;
}
1.2.2 默认执行super()
以下两种情况,Java默认值型super(),调用父类的构造方法。
(1)当一个类没有声明构造方法时,Java为该类提供默认构造方法,调用super()执行父类无参数的构造方法。
public Student() //Java提供的默认构造方法
{
super(); //调用父类构造方法Person()
}
如果父类Person没有声明构造方法Person(),则上述语句产生编译错误。因此,每个类都要声明无参数的构造方法,即使自己不用,也要为子类准备着。
public Person() //Java提供的默认构造方法
{
super(); //调用父类构造方法Object()
}
(2) 如果子类的构造方法没有调用super()或this(),Java将默认执行super()。
public Student()
{
super();
speciality="";
}
1.3 类的多态性
类的多态性表现为方法的多态和类型的多态。
方法的多态:包括方法的覆盖和重载,为一种功能提供多种实现。
类型的多态:子类是一种父类类型。
子类重定义父类成员包括:
(1)重定义父类的成员变量,则隐藏父类的成员变量;
(2)重定义父类的成员方法,如果参数列表相同,则覆盖父类的成员方法,否则重载。
子类重定义父类成员表现出多态,父类对象引用父类成员,子类对象引用子类成员。
在子类的成员方法中,如果需要引用被子类隐藏或覆盖的父类同名成员,可以用super引用。格式如下:
super.成员变量
super.成员方法([参数列表])
子类对象即是父类对象——子类对象包含父类的所有成员变量,isA关系表现为继承具有“即是”性质。 new Person()/Student() instanceof Person
父类对象引用子类实例——父类对象能够引用子类实例
Person p=new Student();
1.3.1 编译时多态和运行时多态
(1)编译时多态
对于多个同名方法,如果在编译时能够确定执行同名方法中的哪一个,则称编译时多态。
方法的重载—都是编译时多态性
方法的覆盖—当对象引用本类实例时,为编译时多态;
否则,运行时多态。
Person p1=new Person("李小明",new MyDate(1979,3,15));
System.out.println("p1:"+p1.toString()); //编译时多态性,执行Person类的toString()
(2)运行时多态
父类对象只能执行哪些在父类中声明、被子类覆盖了的子类方法,如toString(),不能执行子类中新增加的成员方法。
程序运行时,Java从实例所属的类开始寻找匹配的方法执行,如果当前类中没有匹配方法,则沿着继承关系逐层向上,依次在父类和各祖先类中寻找匹配方法,直到Object类。
四 类的抽象性
抽象类特点:1)抽象类中可以不包含抽象方法,但是包含抽象方法的类必须被声明为抽象类;
2)构造方法、静态成员方法不能被声明为抽象方法;
3)一个非抽象类必须实现从父类继承来的所有抽象方法,如果不能实现父类的所有抽象方法,则该类必须声明为抽象类;
4)抽象类不能被实例化,不能创建抽象类实例。