------- android培训、java培训、期待与您交流! ----------
面向对象2
接下来就是面向对象的更加高级的部分了
1.面向对象三大特性之一继承性继承是所有面向对象语言不可缺少的一个组成部分,当你创建一个类时,总是在继承,所以除非明确指出要重那个类中继承,否则就隐式的从 Object 中继承继承的语法很简单,只需要使用 extends 关键字即可例如 class Student extends Person{ } 注意:在java中一个类只能有一个父类,(只允许有一个爹啊),和C++不同(C++支持多继承),但一个父类可以同时拥有很多子类,同时能实现多个接口(干爹可以有很多个)子类继承了父类,自然得到父类的很多东西,包括成员变量(必须是非 private 修饰的)和成员方法,成员方法可以覆盖,但是成员变量就没有这么简单了,后面会说道子类的每个对象也是其父类的对象,反之父类对象不一定是其子类的对象(就像一个人你可以当他是只动物,但是一个动物你不能当他是个人)接下来看一段实例代码
public class Test {
public static void main(String[] args) {
Student s = new Student("张三", 15, 12345, 11111111) ;
s.printId();
System.out.println(s.getId());
}
public Test() {
}
}
class Person{
public String name;
public int age;
public int id;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
}
class Student extends Person {
public int id;
public Student(String name, int age, int schoolid, int personId) {
super(name, age);
this.id = schoolid;
super.id = personId;
}
public int getId() {
return id;
}
public void printId() {
System.out.println("拿到子类的id");
System.out.println(this.getId());
System.out.println("拿到父类的id");
System.out.println(super.getId());
}
}
打印的结果是
拿到子类的id
12345
拿到父类的id
11111111
12345
代码分析:在这个程序中我定义了一个类 Person ,又定义另外一个类Student,该类继承了Person,在Student的构造方法中,第一行有段super(name, age)代码,这段代码的意思是调用父类的指定的构造方法,这里再介绍一个关键字 super ,这个关键字和 this 类似,通过 this 代表当前对象可以调用自己的方法和构造方法,super 则是调用父类的方法和构造方法和this方法一样,super()必须写在子类构造方法中的第一行,先有了父类的对象,才能有资格创建子类的对象(先有老爸后才能有儿子吗,不可能没老爸,突然蹦出个儿子),在这个程序中Person和Student都有一个id属性,子类并没有将其覆盖掉,我过去总是认为一个子类拥有和父类相同的属性,就会将其覆盖掉,父类子类共享一个数据,这是错误的.但是在这个程序中,父类和子类都有一个同名的方法getId(),子类继承他的时候将父类的方法给覆盖掉了,调用s.getId()是调用子类的方法体.说道覆盖,是指父类中有一个方法,子类中有一个一模一样的方法声明,所谓的一模一样是指方法名相同,返回值相同,方法参数列表(参数个数,参数类型)也完全相同,就是执行的方法体不同.还有一点,就是访问权限的事,子类覆盖父类的方法,访问权限一定要比父类的大,或者和父类的权限相等,不能比父类的权限还要小,你如果想调用父类的方法的话,就必须在子类的方法代码块中显示的通过super.getId()才能调用到父类的方法
.
2.final 具体的使用
final 可以用来修饰成员变量,成员方法,类让我们看下面一段代码
public class Test {
public static void main(String[] args) {
Person s = (Person)new Student("张三", 15, 12345, 11111111) ;
//s.printId();
System.out.println(s.getId());
}
public Test() {
}
}
final class Person{
public final String name;
public int age;
public int id;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//声明最终方法,子类无法覆盖
public final int getId() {
return id;
}
}
class Student extends Person {
//public int id;
public Student(String name, int age, int schoolid, int personId) {
super(name, age);
this.id = schoolid;
super.id = personId;
//编译无法通过
super.name = "lishi";
}
public int getId() {
System.out.println(this.name);
return id;
}
}
3抽象类
在java中有一种类不能通过使用 new 关键字来创建对象,但他可以作为一个父类被其他众多的子类所共享,这个类叫做抽象类,抽象类无法创建对象,但是可以拥有自己的构造方法,
构造方法的作用有两个,1.创建对象,2.完成成员变量的初始化动作,虽然无法创建对象,但是成员变量还是要初始化的,抽象类存在的意义就是要被其他类所继承,继承抽象类的类必须
全部覆写父类中的抽象方法,否则,子类将还是抽象类,无法创建对象,如何写抽象类和抽象方法呢,但下面一段代码
修饰符(可加可不加) abstract class 类名 {
//普通方法
修饰符(可加可不加) 返回值 方法名(参数列表){};
//抽象方法
修饰符(可加可不加) abstract 返回值 方法名(参数列表)
}
这里值得注意的是有抽象方法的类一定是抽象类,但抽象类不一定就有抽象方法,这是因为使用 abstract 关键字修饰的类不能创建对象,有人单纯的只是不想自己的类让别人用来创建对象
不管抽象方法什么事
还有 abstract 关键字不能与 private final static 这些关键字混用,这很好理解
1.abstract 这个关键字用来声明抽象方法,抽象方法就是用来重写的,你配合 private 致使子类没有资格覆盖他了,本末倒置,矛盾
2.被 final 修饰的方法是最终方法,你无法覆盖他了,与 abstract 存在意义相抵触,矛盾
3.static 是用来修饰属于字节么文件的变量和方法的,他不需要通过对象调用,也就是说可以通过抽象类名.方法名调用,但是抽象方法没方法体啊,执行什么啊,矛盾
接下来让我们看看抽象类的应用
如果有一个人对你说我要创建一个 Animal 类的对象,你可能很疑惑,Animal本来就是一个非常抽象的一个概念,Animal有很多啊,Cat是Animal,Dog是Animal,Person也是一个Animal,你让我创建
什么呢,这时候你就要考虑把Animal变成一个抽象类,让别人无法创建对象,想创建对象,行啊,你得说清楚具体创建什么东西,我才能帮你创建.
实例代码
public abstract class Test {
public static void main(String[] args) {
((Animal)new Person(15, "人类")).run();
((Animal)new Person(15, "人类")).eat();
new Cat(5, "猫").catchMouse();
}
}
abstract class Animal {
//动物都有自己的年龄
public int age;
public Animal(int age) {
this.age = age;
}
public void eat() {
System.out.println("动物都能进食");
}
//动物都能跑,每个动物跑的方式不同,所以为定义抽象方法
public abstract void run();
//动物都能叫,每个动物叫的声音不同,所以为定义抽象方法
public abstract void say();
}
class Cat extends Animal {
public String name;
public Cat(int age, String name) {
super(age);
this.name = name;
}
public void run() {
System.out.println("用四条腿跑");
}
public void say() {
System.out.println("miao miao");
}
//每个动物我自己特有的能力
public void catchMouse() {
System.out.println("捉老鼠");
}
}
class Person extends Animal {
public String name;
public Person(int age, String name) {
super(age);
this.name = name;
}
public void run() {
System.out.println("用两条腿跑");
}
//每个动物我自己特有的能力
public void swim() {
System.out.println("游泳");
}
public void say() {
System.out.println("用嘴说话");
}
}
4接口
接口是一种非常的特殊类,他比抽象类抽的更加彻底了,抽象类中允许有普通方法,而接口中不允许出现一个普通方法,方法如果没有加修饰符的话,系统会自动帮你加上 public static
抽象类中可以有成员变量,而接口中只允许出现 static final 修饰的常量,常量必须初始化,接口和抽象类一样,不允许创建对象,所以非静态成员变量是没有任何意义的.
下面是接口的语法
public interface 接口名 {
public static final 数据类型 成员变量名=初始值
public abstract 返回值数据类型 方法名(参数列表);
}
5.接口的多重实现以及继承
接口是一种特殊的类,类存在着继承,同理,接口也存在着继承,子接口继承父接口将继承父接口中的所有常量和抽象方法,与类的继承不同的是,类只允许单继承,而接口允许多继承,一个接口
可以可以继承n个接口,如果子接口中存在于父接口相同的常量和方法声明,则父接口中的常量会被隐藏,方法会被覆盖.
实例代码
interface Myinterface1 {
int var1 = 1;
void testMethod1();
}
interface Myinterface2 {
int var2 = 2;
void testMethod2();
}
interface Myinterface3 extends Myinterface1, Myinterface2 {
int var1 = 3;
void testMethod();
}
接口的实现,一个接口无法用来创建对象,他存在的意义是他必须被某个类所实现,实现了这个接口的类必须实现接口中的全部抽象方法,否则就算一个抽象方法没有重写,也只能算是
抽象类,一个类实现一个或者多个接口,必须注意以下三点
1.向上文所说的,如果你打算实现某个接口的类不是抽象类的话,就必须实现全部接口的所有抽象方法,因为非抽象类中不能存在抽象方法吗.
2.实现接口的抽象方法时,方法声明部分必须全部相同,否则只能算是定义了不同的新方法,而不是实现已有的抽象方法
3.注意,接口中的抽象方法权限修饰符默认是public,你实现的时候绝对不能降低它的权限,只能用public,为了避免出错,建议实现方法时,去copy他的原方法,这样不容易出错
什么时候选择继承某个类,还是实现某个接口,这就要看你的面向对象的经验了,举个例子来说吧,人这个类继承了Animal后,每个人都应该有自己的工作吧,有些人是当老师的,有些人
是当厨师的,有些是做程序员的,很多,你不可能都继承吧,java只允许单继承啊,你又不能把所有的工作都放在Person类中,一个Person对象创建出来,这个人又能当老师,又能当厨师
又能重事老师的工作,等等,这个人不是超人了吗.违背客观规律,这时候就要考虑用接口来实现,你是干什么工作的,就实现什么接口,你如果同时做多份工作,就实现多个接口
实例代码
public abstract class Test {
public static void main(String[] args) {
Person p = new Person(25, "张三");
p.study();
p.teach();
p.shaoCai();
}
}
abstract class Animal {
public int age;
public Animal(int age) {
this.age = age;
}
public void eat() {
System.out.println("动物都能进食");
}
//动物都能跑,每个动物跑的方式不同,所以为定义抽象方法
public abstract void run();
//动物都能叫,每个动物叫的声音不同,所以为定义抽象方法
public abstract void say();
}
class Person extends Animal implements Cook, Teacher {
public String name;
public Person(int age, String name) {
super(age);
this.name = name;
}
public void run() {
System.out.println("用两条腿跑");
}
public void qieCai() {
System.out.println("厨师会切菜");
}
public void shaoCai() {
System.out.println("厨师会烧菜");
}
public void study() {
System.out.println("老师会学习");
}
public void teach() {
System.out.println("老师能教学生");
}
public void say() {
System.out.println("用嘴说话");
}
}
interface Cook {
void qieCai();
void shaoCai();
}
interface Teacher {
void teach();
void study();
}
interface Programmer {
void writeProgram();
void playgame();
}
5.面向对象三大特性之二多态性
在前面我们说到方法的重载和覆写,这可以算是java中方法的多态,在java中还存在着对象的多态,有了前面的基础我们现在很好理解多态了
实现多态的三个条件
1.有继承父类,或实现某个接口.
2.覆写父类中的某个方法,或实现接口中的某个方法
3.父类,或接口的引用指向子类对象
实现了以上三个条件才能算是多态
拿上面的那个例子来看
public abstract class Test {
public static void main(String[] args) {
//父类引用指向子类对象
Animal a = new Person(33, "人类");
a.eat();
a.run();
a.say();
}
}
abstract class Animal {
public int age;
public Animal(int age) {
this.age = age;
}
public void eat() {
System.out.println("动物都能进食");
}
//动物都能跑,每个动物跑的方式不同,所以为定义抽象方法
public abstract void run();
//动物都能叫,每个动物叫的声音不同,所以为定义抽象方法
public abstract void say();
}
//Person继承Animal
class Person extends Animal {
public String name;
public Person(int age, String name) {
super(age);
this.name = name;
}
//覆写了父类中的抽象方法
public void run() {
System.out.println("用两条腿跑");
}
//覆写了父类中的抽象方法
public void say() {
System.out.println("用嘴说话");
}
}
这个小程序是典型的多态,用父类的引用指向子类对象的时候,该引用能够访问的只有父类中的成员方法和成员变量,有意思的是,如果子类覆写了父类的方法,那么调用父类的方法时,
确是在执行子类的方法体,子类独有,父类没有的的方法是没有办法得到执行的,想要使用子类特有的方法,只有(Person)a将引用强制向下转型,转型后,就是子类引用指向子类对象了
子类的方法就可以调用了
6面向对象三大特性之三封装性
封装性没什么可说的,就是将数据封装好(用 private 修饰),这样在类外就没有办法随便访问这个数据,这时候,你在定义两个方法,Set方法和get方法,分别用来设置数据和拿到数据
不管他设置什么数据,你都无法阻止,如果你有set和get方法,你把方法提供给他,他就能给属性设置一个值,并且你能在set方法中根据他这个值,判断该不该设置这个值.,这样可以使程序
更加的安全.