7、 面向对象特性
1、准备
对象与类:类是具有类似属性和行为的一类事物的抽象。举例:人是类,那么黄药师就是具体对象。而属性被抽象为类中的成员变量,行为被抽象为成员方法。
成员变量及成员方法:成员变量通常使用private修饰,阻止本类以外的其他类访问。成员与局部变量可以重名,但是需要使用this区分,使用this访问的为成员变量,直接访问的为局部。在方法内访问变量,如果没有该名称的局部变量会自动查找是否有该名称的成员变量。正常定义成员方法时,一般是不需要添加static修饰符的,分为两种:get或set方法和属于类的功能的方法。
成员变量及局部变量区别:
类中的位置 | 内存中的位置 | 生命周期 | 初始化值 | |
---|---|---|---|---|
成员变量 | 类中,方法外 | 堆内存 | 随着对象的创建而存在,随着对象的消失而消失 | 有默认 |
局部变量 | 方法中或者方法声明上(形式参数) | 栈内存 | 随着方法的调用而存在,随着方法的调用完毕而消失 | 没有默认值。必须先定义,赋值,最后使用 |
建议同学们查查内存分析图,博客不贴。
2、封装
原则:将不需要对外提供的内容都隐藏起来。把属性隐藏,提供公共方法对其访问。成员变量private,提供对应的get、set方法。
优势:通过方法来控制成员变量的操作,提高了代码的安全性。把代码用方法进行封装,提高了代码的复用性。
private关键字:是一个权限修饰符。可以修饰成员(成员变量和成员方法)。被private修饰的成员只在本类(包括其对象)中才能访问。
this关键字:一般出现在类的一个方法的定义当中,代表当前对象的引用。我们通常用其将本对象中的成员与其他作用域区分开来。
public class StudentTest {
public static void main(String[] args) {
Student a=new Student();
Student b=new Student();
a.setName("龙王");
a.setScore(98);
b.setName("独步王");
b.setScore(96);
a.compare(b);
System.out.println("参赛者:"+b.getName()+"和"+a.getName()+";刀法能力评判分别为:"+b.getScore()+","+a.getScore());
}
}
class Student{
private String name;
private int score;
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public String getScore(){return score;}
public void setScore(){this.score=score;}
public void compare(Student s){
if(this.score>s.score(){
System.out.println("胜者是:"+this.name);
}else{System.out.println("胜者是:"+s.name);}
}
}
3、继承
概念:如果多个类具有相同的属性和行为,我们可以抽取出共性的内容定义父类,这时再创建相似的类时只要继承父类即可。子类拥有父类的所有属性与方法,无需重新定义。并且可以直接使用非私有的父类成员。举例:父类——动物,子类——猫科、犬科,具体对象——斑点狗。
注意:Java只支持单继承,不支持多继承。即只能有一个父类。父类可以继续有父类。所有类均有父类,只有Object类没有父类。在所有使用父类类型的地方均可以传入其子类对象。构造器Constructor不能被继承,因此不能重写Override,但可以被重载Overload。
方法重写:子类可以按照子类自身的逻辑重新定义继承过来的父类方法,这个重新定义一个方法的过程叫做方法重写。子类重写方法时,在声明前加@Override可检测该方法是否为重写的方法。访问权限相同或子类方法访问权限更大(访问权限顺序public>默认)。方法名、参数列表、返回值为基本类型时必须相同,返回值为引用类型时相同或子类小。
public class Test{
public static void main(String[] args) {
Chinese c = new Chinese();
c.setName("张三");//父类继承方法直接调用
String name = c.getName(); //父类继承方法直接调用
System.out.println(name); //打印结果为张大力
c.eat(); //方法重写后调用的为重写后的方法,按照中国的习惯,使用筷子吃
}
}
class Person{
private String name;
void eat(){System.out.println("吃饭");}
public String getName(){return name;}
public void setName(String s){this.name=s;}
}
class Chinese extends Person{
@override //@override是用于强制规定当前定义的方法一定为重写的方法
public void eat() {System.out.println("按照中国的习惯,使用筷子吃");}
}
抽象:抽象类用来描述一种类型应该具备的基本特征与功能, 具体如何去完成这些行为由子类通过方法重写来完成。抽象方法指只有功能声明,没有功能主体实现的方法。具有抽象方法的类一定为抽象类。
使用:抽象类无法直接创建对象,只能被子类继承后,创建子类对象。子类需要继承抽象父类并完成最终的方法实现细节(即重写方法,完成方法体)。而此时,方法重写不再是加强父类方法功能,而是父类没有具体实现,子类完成了具体实现,我们将这种方法重写也叫做实现方法。只有覆盖了抽象类中所有的抽象方法后,其子类才可以实例化。如果存留未实现的抽象方法则该子类仍为一个抽象类,无法创建对象。抽象类不一定包含抽象方法。抽象类可以有非抽象方法。
public class Test {
public static void main(String[] args) {
//Animal q = new Animal();抽象类不能创建对象
Dog d = new Dog();
d.bark();
d.sleep();
d.eat();
}
}
abstract class Animal{//abstract在访问权限后,返回值类型前修饰方法,方法没有方法体:
public abstract void bark();
public abstract void sleep();
public void eat(){System.out.println("吃");}
}
class Dog extends Animal{
@Override
public void bark() {System.out.println("狗汪汪叫!");}
@Override
public void sleep() {System.out.println("趴着睡");}
}
4、多态
接口:接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的”类”。接口只描述所应该具备的方法,并没有具体实现,具体的实现由接口的实现类(相当于接口的子类)来完成。这样将功能的定义与实现分离,优化了程序设计。接口的更为抽象表现为其内的所有方法均为抽象方法,同时不定义普通的成员变量(可以定义静态常量)。
定义:与定义类的class不同,接口定义时需要使用interface关键字。定义接口所在的仍为.java文件,虽然声明时使用的为interface关键字的编译后仍然会产生.class文件。
注意:如同类继承类后便拥有了父类的成员,可以使用父类的非私有成员。A接口继承B接口后,A接口便拥有了A、B两个接口中所有的抽象方法。Java支持一个类同时实现多个接口。 一个类可以有多个接口书写加上逗号即可implements List,RandomAccess,Cloneable。接口中的成员是有固定修饰符abstract的,如果没有写,也会自动加入:(接口中都是常量没有变量)。
public class Test {
public static void main(String[] args) {
DrugDog a= new DrugDog();
a.eat();
a.bark();
a.captureDrug();
}
}
interface CaptureDrug{
public abstract void captureDrug();
}
abstract class Dog{
public abstract void eat();
public void bark(){System.out.println("汪汪");}
}
class DrugDog extends Dog implements CaptureDrug{
public void eat(){System.out.println("吃");}
public void captureDrug(){System.out.println("缉毒");}
}
多态:Java中多态的代码体现在一个子类对象(实现类对象)既可以给这个子类(实现类对象)引用变量赋值,又可以给这个子类(实现类对象)的父类(接口)变量赋值。最终多态体现为父类引用变量可以指向子类对象。多态的前提是必须有子父类关系或者类实现接口关系,否则无法完成多态。在使用多态后的父类引用变量调用方法时,会调用子类重写后的方法。多态配合继承与方法重写提高了代码的复用性与扩展性,如果没有方法重写,则多态同样没有意义。
instanceof关键字:通过instanceof关键字来判断某个对象是否属于某种数据类型。
boolean b = 对象 instanceof 数据类型
转型:多态本身是子类类型向父类类型向上转型的过程。向上转型:当有子类对象赋值给一个父类引用时,便是向上转型,多态本身就是向上转型的过程。向下转型:一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用转为子类引用,这个过程是向下转型。如果是直接创建父类对象,是无法向下转型的!
细节:编译时,检查父类引用变量的数据类型是否包含对应的成员方法与成员变量。运行时,成员方法调用子类重写方法,没有用private修饰的成员变量访问时,访问的为父类类型的。
public class Test {
public static void main(String[] args) {
Father f= new Father();
f.method();
Son s= new Son();
s.method();
Father f2= new Son();//多态本身就是向上转型。向上转型后,一切表现形式都是父类的表现形式,不能调用子类特有的功能
f.method();//打印父类方法
System.out.println(f2.name);//父亲
Son s2=(Son)f2;//向下转型,使用强制类型转换进行转换,向下转向那个后可以调用子类特有方法
s2.method();//打印子类方法
System.out.println(s2.name);//儿子
}
}
class Father{
String name="父亲";
public void method(){System.out.println("父类方法");};
}
class Son extends Father{
String name="儿子";
@Override
public void method(System.out.println("子类方法");){}
}
上一篇: Java基础学习笔记01