Java快速入门--4--面向对象

java几乎是最好面向对象的语言了,和C++相比,你会感觉到java的面向对象部分是多么简洁。

面向对象概念

在真实的世界里,不管是我们人,还是动物,还是机器,我们都可以称之为一个对象,他们都有共同的特点,这个特点是,他们都是一堆属性的集合,所以,我们把拥有一堆属性的集合体,称为一个对象。例如,人,可以有名字,可以有年龄,可以有性别等等属性,如果我们抽象出来,那么就是一个对象,在java中如何定义一个对象呢?

public class Person{
    int age;
    String name;
    char sex;
}

这样就构造了一个Person对象,例如,我们把它定义成,诸葛先生。

    public static void main(String[] args) {
        Person person = new Person();
        person.name = "诸葛先生";
        person.age = 20;
        person.sex = '男';
    }

如果你以后想使用这个对象,那么只需要将person传递过去就可以了。
但是,久而久之,我们发现,直接通过person.name = “”这种通过 ‘.’直接调用属性或赋值属性,是非常不安全的,例如,我们只希望这个诸葛先生,只能被赋值,而不能被取值,那么应该怎么办呢?接下来,请看对象的访问权限

对象的访问权限

如果我们只希望,我们定义一个诸葛先生对象,但是,不想透露他的年龄,那么我们该怎么做呢?
在java中,提供了三种权限控制的关键字,这个跟C++中几乎是一模一样的。
public 公共的,可以直接为外部提供服务
private 私有的,不能直接为外部提供服务,只能为自己内部使用
protected 保护的,该关键字用在继承中,到后面讲到继承的时候再来讲这个关键字。
让我们来重新定义这个类


public class Person {
    private int age;
    private String name;
    private char sex;   
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public char getSex() {
        return sex;
    }
    public void setSex(char sex) {
        this.sex = sex;
    }
    public void say(){
        System.out.println("我是" + this.name);
    }   
}

我们照样的定义一个person对象

Person person = new Person();
person.setAge(20);
person.setName("诸葛先生");
person.setSex('男');

这样,我们同样的构造了一个诸葛先生对象,但是,你会发现,这里的三个属性都被private修饰了,而且,age没有被提供get方法,这时候,你就没有办法听过person.age或者person.getAge()来获取到诸葛先生的真实年龄了,这也就是一种权限控制策略,心细的同学可能会发现,上面多了一个this,这又是什么呢?事实上,this就是指的当前对象。如果你定义的是person1对象,那么this就是代表的person1对象,如果你定定义的是person2对象,那么this就是代码的person2对象,也就是说,这个this指代的是字节。

构造函数

有人会说,上面这中初始化方法,太麻烦了,我们构造一个诸葛先生对象,居然要在后面调用3次person….啥的,有没有更简单一点的方法?答案是有的。

public class Person {
    private int age;
    private String name;
    private char sex;   
    public Person(int age,String name,char sex){
        this.age = age;
        this.name = name;
        this.sex = sex;
    }
    public String getName() {
        return name;
    }
    public char getSex() {
        return sex;
    }
    public void say(){
        System.out.println("我是诸葛先生");
    }
}

这时候,我们在使用的时候

Person person = new Person(20,"诸葛先生",'男');
System.out.println(person.getName());

构造函数的命名规则是名字必须和类名相同,没有返回值,如果构造函数前面不写public,那么默认的权限的包权限,也就是同一级目录下才能使用,否则就会new失败,在C++中,如果我们在构造函数前面什么都不写,编译器默认修饰成private,而在java中,我们称它为default

继承

我们前面学了类和对象,如果我们希望某个类复用其他类的属性和方法,那么可以使用继承来实现。

public Animal{
    protected String name;
    protected char sex;
    public void setName(String name){
        this.name = name;
    }
    public void setSex(char sex){
        this.sex = sex;
    }
    public void getName(){
        return this.name;
    }
    public void getSex(){
        return this.sex;
    }
    public void say(){}
}

public Dog extends Animal{
    public void say(){
        System.out.println("汪");
    }
}
public Cat extends Animal{
    public void say(){
        System.out.println("喵");
    }
}

我们定义了一个Animal对象,同时让dog和cat继承于animal,这时候,这个两个类中也就包含了animal中的方法了,但是如果, animal中是用private修饰的,那么将不会继承这个属性或方法。

Cat cat = new Cat();
car.setName("阿猫");
System.out.println(cat.getName);
Dog dog = new Dog();
dog.setName("阿狗");
System.out.println(dog.getName());

使用继承的时候,构造函数的执行顺序

我在使用继承的时候,事实上,是先执行父类的构造函数,然后再执行子类的构造函数,在内存中,事实上,存在两个对象,两个对象都被同一个标识符引用。

public class Test extends Test2{
    public Test(){
        super("哈哈");
        System.out.println("我是子类的构造方法");
    }
    public static void main(String[] args) {
        System.out.println(new Test().getName());;
    }
    public int getNum(){
        return 1;
    }
}

class Test2{
    protected String name;
    public Test2(String name){
        this.name = name;
        System.out.println("我是父类的构造方法");
    }
    public String getName(){
        return this.name;
    }
    public int getNum(){
        return 1;
    }
}

你会发现,上面先打印的是我是父类的构造方法,再打印的我是子类的构造方法,再打印哈哈,这就体系了,先执行的是父类的构造方法,如果我们不写这个super(“哈哈”),那么这个端程序是有问题的,如果不写,编译器会帮我们自动调用父类中午参构造方法,我们知道,如果我们在父类中定义了其他有参构造方法,那么,就不会再默认定义一个无参构造方法了,不管怎么样,先被调用的都是父类的构造函数。

父类引用指向子类对象

有上面的例子,
我们完全可以这么做,让父类引用指向子类对象。

Test2 t = new Test();
System.out.println(t.getNum());

上面打印的是2,而不是1,也就是说,如果子类和父类中有相同的方法,那么调用是执行的子类中的方法,而不是父类中的方法,这就是多态,你想想,如果很多类都继承这个Test,都有一个getNum()方法,是不是想要调哪个类中的方法,我们就new哪个类就可以了?我们根本不必关系要用哪个类来引用了,因为他们统统都可以用父类来引用。拿上面哪个动物的例子来说明吧。
cat和dog都继承了animal,而我们现在有如下一个函数

public static void listen(Animal animal){
    System.out.println("我听到有动物在喊" + animal.say());
}

你会发现,你如果我们使用这个方法,根本不用关心传过来的是dog还是cat,它都能调用say();方法,有了这个,我们是不是就可以实现定义好一套接口,供后面的人使用,我也不知道对方要在say里面写什么,但是,我这里确实可以调用对方的say方法,这就是多态的神奇之处,你会发现,它居然可以调用未来别人定义的方法。事实上,这个地方在C++快速入门中也有解释,只不过在C++中要使用virtual关键字修饰,否则就不会产生多态,调用的是自身的方法。

抽象类

含有抽象方法的类叫抽象类,抽象方法,也就是一个方法模板,里面没有实现,在上面的例子你会发现,我们在Animal中什么都没有写,这时候,就可以定义成一个抽象方法。
抽象类的定义方法

public abstract class Animal{
    protected String name;
    protected char sex;
    public void setName(String name){
        this.name = name;
    }
    public void setSex(char sex){
        this.sex = sex;
    }
    public void getName(){
        return this.name;
    }
    public void getSex(){
        return this.sex;
    }
    public abstract void say();
}

在抽象类中,可以有抽象方法,也可以有普通方法。

#

接口

如果一个类中,全部是抽象方法,我们可以将它定义成一个接口,接口的定义方法是

public interface A{
    public void say();
}

实现这个接口

public class B implements A{
    @Override
    public void say(){
        System.out.println("hello");
    }
}

那么,定义成接口有什么好处呢?为什么不使用继承呢?原因是,使用接口,同样的可以实现多态,在java中,只允许单继承的方法,所以如果你这里继承了,以后就没有位置继承了,这里定义成接口,为程序的可拓展性奠定了基础。

猜你喜欢

转载自blog.csdn.net/qq_25956141/article/details/79703789