首页 > 编程语言 > 详细

java入门篇6 --- 面向对象基础

时间:2020-01-07 20:25:36      阅读:86      评论:0      收藏:0      [点我收藏+]

java是一款面向对象语言,接下来进入java的入门

首先java是有类的概念,类由属性跟方法,而每个类跟属性都可以设置public跟private,区别就是能否被外部访问,就跟python中设置类属性,类方法一样,如果我们外部访问类的私有属性或方法,就会报错。

this指针始终指向调用者,与python一样

class Person{
    public String name;
    private int age;

    public int getAge(){
        return this.age;
    }
    public void setAge(int age){
        this.age = age;
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        Person p = new Person();
        // p.age = 25;  // Error:(18, 10) java: age 在 Person 中是 private 访问控制
        p.name = "小明";
        System.out.println(p.getAge());  // 0
        p.setAge(25);
        System.out.println(p.getAge());  // 25
        System.out.println(p.name);  // 小明
    }
}

下面来看一下私有方法,从报错来看,私有方法如果外部访问也会报错,因此如果对于一些敏感信息,限制信息,可以定义为私有的,然后定义一个方法接口进行限制,然后在返回就可以了

class Person{
    public String name;
    private int age;

    public int getAge(){
        return this.age;
    }
    public void setAge(int age){
        this.age = age;
    }

    private int xuSui(){
        return this.age + 1;
    }
    public int getXuSui(){
        return this.xuSui();
    }

}

public class HelloWorld {
    public static void main(String[] args) {
        Person p = new Person();
        // p.age = 25;  // Error:(18, 10) java: age 在 Person 中是 private 访问控制
        p.name = "小明";
        p.setAge(25);
        // System.out.println(p.xuSui());  // Error:(27, 29) java: xuSui() 在 Person 中是 private 访问控制
        System.out.println(p.getXuSui());  // 26
    }
}

看到初始化就想到,这个初始化难道没有构造方法吗?有的,接下来就来看一下构造方法

class Person{
    private String name;
    private int age;
    // 构造方法
    public Person(String name, int age){
        this.name = name;
        this.age =age;
    }
    // 构造方法,一般如果我们没有创建构造方法,系统会给我们默认创建一个这样的构造方法
    public Person(){}

    public String getName(){
        return this.name;
    }
    public int getAge(){
        return this.age;
    }

}

public class HelloWorld {
    public static void main(String[] args) {
        Person p1 = new Person();
        Person p2 = new Person("小明", 25);
        System.out.println(p1.getAge());  // 0
        System.out.println(p1.getName()); // null
        System.out.println(p2.getAge());  // 25
        System.out.println(p2.getName());  // 小明
    }
}

从上述代码可以看出,一个类可以有多个构造方法,并且初始化如果没有赋值,默认为空值,那接下来我们看一下,这个赋值过程是什么样子的,如果在类内部声明属性的时候就给他个值是什么情况

class Person {
    private String name = "小红";
    private int age = 18;

    // 构造方法
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 构造方法,一般如果我们没有创建构造方法,系统会给我们默认创建一个这样的构造方法
    public Person() {
    }

    public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }

}

public class HelloWorld {
    public static void main(String[] args) {
        Person p1 = new Person();
        Person p2 = new Person("小明", 25);
        System.out.println(p1.getAge());  // 18
        System.out.println(p1.getName()); // 小红
        System.out.println(p2.getAge());  // 25
        System.out.println(p2.getName());  // 小明
    }
}

从结果可以看出,这个会执行属性的初始化,然后在执行构造方法

接下来,学了类了,我们在使用String.indexof时,不是有很多可以调用吗?那个就是方法重载,顾名思义,就是方法名,返回值都是一样的,可能就是参数以及代码块有所不同,如下所示

class Print {
    public void print() {
        System.out.println("null");
    }

    public void print(char s) {
        System.out.printf("char:%s", s);
    }

    public void print(int s) {
        System.out.printf("int:%d", s);
    }

    public void print(float s) {
        System.out.printf("float:%f", s);
    }

}

public class HelloWorld {
    public static void main(String[] args) {
        Print p = new Print();
        p.print();  // null
        p.print(‘a‘);  // char:a
        p.print(1);  // int:1
        p.print(1.08f);  //float:1.080000

    }
}

接下来看一下继承,继承的关键字就是extends,前端也是这个写的,所有的类除了基类,都有且仅有一个父类,如果没有extends类,默认是继承object类,跟python也是一样的

如果new一个子类,可以使用父类来声明,因此子类是包含父类的。

另外,类的实例也是可以进行转化的,但只能???子类向父类转化,不能反过来,转化为父类之后,就访问不到子类中的方法了;

class Person {
    private String name;  // private定义的私有化,子类是访问不到的
    protected int age;  // 自身,子类及同一个包中类可以访问,外部包无法访问,外部包后续在说

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return this.name;
    }
}

class Student extends Person {
    private float score;

    public Student(String name, int age, float score) {
        super(name, age);  // 如果父类没有构造方法,或者构造方法参数不一致,会报错,super就是继承父类构造方法
        this.score = score;
    }

    public float getScore() {
        return this.score;
    }

    public void print() {
        System.out.println(this.age); // 18
//        System.out.println(this.name);  // Error:(26, 32) java: name 在 Person 中是 private 访问控制
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        Person p = new Person("ming", 25);
        System.out.println(p.age);  // 25
        Student s = new Student("hong", 18, 60.0f);
        System.out.println(s.age);  // 18
        System.out.println(s.getName());  // hong
        System.out.println(s.getScore());  // 60.0
        s.print();
        Person m = new Student("mei", 30, 99.0f);
        // Student mm = new Person("mei", 30);  // Error:(43, 22) java: 不兼容的类型: Person无法转换为Student
        System.out.println(m instanceof Person);  // true  instance中文意思实例,判断名是否是Person的实例
        System.out.println(m instanceof Student);  // true
        // System.out.println(m.getScore());  // Error:(46, 29) java: 找不到符号符号:   方法 getScore() 位置: 类型为Person的变量 m

        Student n = (Student) m;  // 类型的强制转化
        System.out.println(n instanceof Person);  // true
        System.out.println(n instanceof Student);  // true
        System.out.println(n.getScore());  // 99.0
    }
}

 

另外,关于这个声明是否可被访问的关键字的范围如下:

   类内部  本包  子类 外部包 
public   √  √  √  √
protected  √  √  √  ×
default   √  √  ×  ×
 private  √  ×  ×  ×

从上面的表中可以看出,private除了类内部,其他都访问不到。

接下来看一下多态:

@Override建议如果是重写方法的话要带上,这样编译器会帮助我们检查,要不然玩意手抖把参数写错了,那就是重载了。。

根据下面的例子,理解多态的含义:java实例调用的方法是基于运行时实际类型的动态调用,这就是多态

class Person {
    public String eat(String food) {
        System.out.println("Person eat something");
        return food;
    }

    public void run() {
        System.out.println("Person running");
    }

    public int cal(int s) {
        return s;
    }

    // final 可以指定该方法不可以被重写
    final void tell() {
        System.out.println("Person is talking");
    }
}

class Student extends Person {
    // 重写 override
    @Override  // 非必需的,这个就是编译器会帮助我们在编译时检查错误
    public String eat(String food) {
        System.out.println("Student eat something");
        return food;
    }

    // 方法签名一样,但是返回值不一样,会报错
    // @Override  // java: 方法不会覆盖或实现超类型的方法
//    public int run() {   // java: Student中的run()无法覆盖Person中的run() 返回类型int与void不兼容
//        System.out.println("Person running");
//        return 1;
//    }
    // 重载  overload
    public int run(int s) {   // Error:(18, 16) java: Student中的run()无法覆盖Person中的run() 返回类型int与void不兼容
        System.out.println("Student running");
        return s;
    }

    @Override
    public int cal(int s) {
        return super.cal(s) * 2;  // super可以调用已经被覆盖的父类方法
    }

//    @Override
//    public void tell(){  // ava: Student中的tell()无法覆盖Person中的tell()被覆盖的方法为final
//        System.out.println("Student is talking");
//    }
}

public class HelloWorld {
    public static void main(String[] args) {
        Person p = new Person();
        Person s = new Student();
        s.eat("egg");  // Student eat something, 因此可以确定,java实例调用的方法是基于运行时实际类型的动态调用,这就是多态
        // s.run(1);  // 会报错,因为声明的是person类型,但是调用student方法
        Student s1 = new Student();
        s1.run();  // Person running 因为方法签名跟返回值不同,因此 run是重载
        s1.run(1);  // Student running
        System.out.println(p.cal(1));  // 1
        System.out.println(s.cal(1));  // 2  这个也说明java是基于运行时候实例指向的类型进行动态调用
        System.out.println(s1.cal(1));  // 2
        s.tell();  // Person is talking
        s1.tell();  // Person is talking

    }
}

看到一个例子,将如何扣税,对于多态讲的挺好,自己写了一下

class Income {
    protected double income;

    public Income(double income) {
        this.income = income;
    }

    public double getTax() {
        return income * 0.15;
    }
}

class NormalIncome extends Income {

    public NormalIncome(double income) {
        super(income);
    }
    // 重写getTax,个人超过五千要交0.1的税
    @Override
    public double getTax() {
        if (this.income < 5000) {
            return 0;
        }
        return (this.income - 5000) * 0.10;
    }
}

class GWYIncome extends Income {
    public GWYIncome(double income) {
        super(income);
    }
    // 重写getTax,含义就是不交税
    @Override
    public double getTax() {
        return 0;
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        Income[] m = new Income[]{new Income(3000), new NormalIncome(5500), new GWYIncome(6000)};
        double total = 0;
        for (Income i : m) {
            total += i.getTax();
        }
        System.out.println(total);
    }
}

工厂模式:

这个词应该很熟悉吧,比如说我定义了一个工厂,那我定义工厂必须实现定义车间,但我在这个类中不会进行具体实现,具体实现由子类实现,并且子类必须实现,

java的抽象类就是工厂模式,并且在声明类时,使用的时车类,而不是宝马类等。。

抽象类是无法实例化的,关键词是abstract,如果子类有必须实现的方法,那么需要在方法字段上声明

abstract class Car {
    protected int wheelNum;

    public Car(int num) {
        this.wheelNum = num;
    }

    public abstract void run();

    public abstract void printWheelNum();

    public void start() {
        System.out.println("car started");
    }
}

class BMW extends Car {
    public BMW(int num) {
        super(num);
    }

    @Override
    public void run() {
        System.out.println("BMW is running");
    }

    @Override
    public void printWheelNum() {
        System.out.printf("BMW wheel num %d", this.wheelNum);
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        // Car c = new Car();  // java: Car是抽象的; 无法实例化
        Car b = new BMW(4);
        b.run();  // BMW is running
        b.start();  // car started
        b.printWheelNum();  // BMW wheel num 4
    }
}

接口:这个go里面也有接口,感觉都差不太多,go里面的接口比java里面功能更多

java里面的接口使用:如果抽象类中没有属性,建议使用接口,另外一个类实现多个接口,类实现接口的关键词是implements,接口就是比抽象类更进一步抽象,另外接口中可以使用default关键字,这个这个方法可以不被重写,其余的要实现这个接口,必须实现其内部所有方法,如果实现了多了接口,想要调用全部方法,需要声明子类类型,否则使用对应接口方法,就用相应的接口类型,不要使用该接口为定义的方法

interface Car {
    void run();

    int getWheelNum();

    default void addWheelNum() {
        System.out.println(getWheelNum() + 1);
    }
}

interface Window {
    void printWindow();
}

class BMW implements Car, Window {
    private int wheelNum;
    private String window;

    public BMW(int num, String window) {
        this.wheelNum = num;
        this.window = window;
    }

    @Override
    public void run() {
        System.out.println("BMW is running");
    }

    @Override
    public void printWindow() {
        System.out.printf("BMW window is %s", this.window);
    }

    @Override
    public int getWheelNum() {
        return this.wheelNum;
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        Car b = new BMW(4, "glass");
        b.run();  // BMW is running
        b.addWheelNum();  // 5
        System.out.println(b.getWheelNum());  // 4
        // b.printWindow();  // java: 找不到符号  符号:   方法 printWindow() 位置: 类型为Car的变量 b
        Window a = new BMW(4, "glass");
        // a.addWheelNum();  // java: 找不到符号 符号:   方法 addWheelNum() 位置: 类型为Window的变量 a
        a.printWindow();  // BMW window is glass
    }
}

静态方法和静态属性

声明的关键字段是 static,这个属性跟方法是字段的,实例访问的时候,会先编程原类,为什么呢?

类有一个命名空间。实例对象有一个命名空间,如果实例对象中没有你要访问的东西,就回去类的命名空间中找。

class Person {
    private String name;
    public static int n;  // 声明静态字段,只有类可以调用

    public Person(String name) {
        this.name = name;
    }

    // 声明静态方法,只有类可以调用
    public static void print() {
        // System.out.println(this.name);  // java: 无法从静态上下文中引用非静态 变量 this,静态方法中无法使用this指针
        System.out.println("i ma static print");
    }

    public String getName() {
        return this.name;
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        Person p1 = new Person("ming");
        Person p2 = new Person("hong");
        System.out.println(p1.n);  // 0 这里为什么可以通过实例访问呢,是因为编译器已经将这个实例转化为类进行调用的n,下面调用静态方法相同
        p1.n = 10;
        System.out.println(p2.n);  // 10
        Person.n = 100;
        System.out.println(p1.n);  // 100
        System.out.println(Person.n);  // 100
        p2.print();  // i ma static print
        Person.print();  // i ma static print

    }
}

接口的静态属性

接口静态属性完整字段应该是:public static final int MALE= 1; 但是接口中属性只能定义静态的,因此就省略了

interface Person {
    int MALE = 1;

    void getMale();
}

class Student implements Person {
    public void getMale() {
        System.out.println(this.MALE);
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        Person p = new Student();
        p.getMale();  // 1
        Student s = new Student();
        s.getMale();  //1 
    }
}

包:

Java内建的package机制是为了避免class命名冲突;

JDK的核心类使用java.lang包,编译器会自动导入;

JDK的其它常用类定义在java.util.*java.math.*java.text.*,……;

包名推荐使用倒置的域名,例如org.apache

作用域:

如果不确定是否需要public,就不声明为public,即尽可能少地暴露对外的字段和方法。

把方法定义为package权限有助于测试,因为测试类和被测试类只要位于同一个package,测试代码就可以访问被测试类的package权限方法。

一个.java文件只能包含一个public类,但可以包含多个非public类。如果有public类,文件名必须和public类的名字相同。

Java内建的访问权限包括publicprotectedprivatepackage权限;

Java在方法内部定义的变量是局部变量,局部变量的作用域从变量声明开始,到一个块结束;

final修饰符不是访问权限,它可以修饰classfieldmethod

一个.java文件只能包含一个public类,但可以包含多个非public类。

java入门篇6 --- 面向对象基础

原文:https://www.cnblogs.com/yangshixiong/p/12163034.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!