web后端入门

java面向对象----基础进阶01

2020-11-20  本文已影响0人  睡前听卡农
1.类:一个Java代码中可以定义多个类,但是只有一个类是用public修饰的,而且public修饰的类名必须成为代码文件的名称。
2.定义类的格式:

修饰符 class 类名{

成员变量:描述类和对象的属性信息。

成员方法:描述类或对象的行为信息的。

构造器:初始化一个类对象并返回引用。

代码块:

内部类:

}

3.构造器的格式:

修饰符 类名(形参){

}

4.构造器初始化对象的格式:

类名 对象名称=new 构造器;

一个类默认有一个无参构造器,不写也存在,但是写了之后会覆盖无参构造器。

5.this关键字

this代表当前对象的引用。

this可以用在实例方法和构造器中。

this用在方法中,谁调用这个方法,this就代表谁。

this用在构造器,代表构造器正在初始化那个对象的引用。

一、java的三大特征(封装、继承、多态)

1.封装
作用:1.可以提高安全性。
2.可以实现代码的组件化。
规范/要求:
1.建议成员变量都私有,使用prvate修饰的方法,成员变量,构造器只能在本类使用。
2.提供成套的getter/setter方法暴露成员变量的取值和赋值,public修饰符,是公开的意义。
小结:
封装的核心思想:合理隐藏,合理暴露。
封装已经成为Java代码的风格,即使代码毫无意义,还是要按照封装的规范写代码。
成员变量私有,提供getter+setter方法。
static关键字:我们定义了很多的成员变量,比如(name,age,sex)我们只写了一份,但是发现很多的对象都可以使用,就说明java中这些成员变量或者方法是存在所属性的,有些是属于对象的,有些是属于类本身的。
java是成员变量是否具有static关键字修饰来区分是属于类的还是属于对象的。

成员变量

1.静态成员变量(类变量)
有static修饰的,属于类本身的,与类一起加载一次,使用类名直接访问即可。
类名.静态成员变量
对象.静态成员变量
2.实例成员变量
对象.实例成员变量
属于类的每个对象的,与类的对象一起加载,对象有多少个就加载多少次。

成员方法

1.静态方法
有static修饰的成员方法叫静态方法也叫类方法,属于类本身,使用类名直接访问即可。
2.实例方法
无static修饰的成员方法叫实例方法,属于类每个对象的,必须使用类的对象来访问。
package com.itppf.成员变量的访问;

public class Student {
    public static String name="李四";
    public String sex;


    public static void main(String[] args) {
        //注意,静态变量可以使用类名或者对象名来调用
        System.out.println(Student.name);
        //在同一个类中,省略类名
        System.out.println(name);
        //如果使用对象名
        Student student=new Student();
        student.name="张三";
        student.sex="男";
        System.out.println(student.name);


        //注意,实例变量不能使用类名来调用
//        System.out.println(Student.sex);
       //实例变量但是可以使用对象来调用
        System.out.println(student.sex);
    }
}

注:在同一个类当中,可以直接使用类名.方法来调用实例方法。但是不推荐,可以创建对象来调用。


2.继承
继承的优势就是把相同的代码写在父类中,提高代码的复用性。
简单案例一:教务系统
角色一:老师(姓名,年龄,性别,身高,活动,教课)。
角色二:学生(姓名,年龄,性别,身高,学习,成绩)。
角色三:管理员(姓名,年龄,性别,身高,操作)。
package com.itppf.继承;

public class Person {
    private String name;
    private String sex;
    private int age;
    private double height;
    private double weight;

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

    public void setSex(String sex){
        this.sex=sex;
    }
    public String getSex(){
        return this.sex;
    }

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

    }

    public void setHeight(double height){
        this.height=height;
    }
    public double getHeight(){
        return this.height;
    }

    public void setWeight(double weight){
        this.weight=weight;
    }
    public double getWeight(){
        return this.weight;
    }

}
package com.itppf.继承;

public class Student extends Person {
    public void action(){
        System.out.println(this.getName()+"学生学习");
    }
}
package com.itppf.继承;

public class Teacher extends Person{
    public void teach(){
        System.out.println(this.getName()+"老师教课");
    }
}
package com.itppf.继承;

public class Administrator extends Person{
public void option(){
    System.out.println(this.getName()+"进行操作");
}
}
package com.itppf.继承;

public class Test {
    public static void main(String[] args) {
        Person p1=new Student();
        Person p2=new Teacher();
        Person p3=new Administrator();

        p1.setName("学生1");
        p1.setAge(12);
        p1.setHeight(180.0);
        p1.setWeight(140.00);
        System.out.println("学生姓名:"+p1.getName());
        System.out.println("学生年龄:"+p1.getAge());
        System.out.println("学生身高:"+p1.getHeight());
        System.out.println("学生体重:"+p1.getWeight());
        ((Student) p1).action();
        System.out.println("****************");
        p2.setName("老师1");
        p2.setAge(12);
        p2.setHeight(180.0);
        p2.setWeight(140.00);
        System.out.println("老师姓名:"+p2.getName());
        System.out.println("老师年龄:"+p2.getAge());
        System.out.println("老师身高:"+p2.getHeight());
        System.out.println("老师体重:"+p2.getWeight());
        ((Teacher) p2).teach();
        System.out.println("****************");
        p3.setName("管理员1");
        p3.setAge(12);
        p3.setHeight(180.0);
        p3.setWeight(140.00);
        System.out.println("管理员姓名:"+p3.getName());
        System.out.println("管理员年龄:"+p3.getAge());
        System.out.println("管理员身高:"+p3.getHeight());
        System.out.println("管理员体重:"+p3.getWeight());
        ((Administrator) p3).option();
        System.out.println("****************");

    }
}
继承不了东西:
1.构造器继承不了,构造器父类是初始化自己的(子类可以使用,但是这里不是继承而是共享)。
有争议的观点:
1.父类的私有成员变量和方法。
2.父类的静态成员变量。
package com.itppf.子类无法继承;

public class Animal {
    public  String name;
    public void eat(){
        System.out.println("动物可以吃东西!");
    }
}
//创建子类
package com.itppf.子类无法继承;

public class Cat extends Animal{
}
//创建测试类,程序入口
package com.itppf.子类无法继承;

public class Test {
    public static void main(String[] args) {
        Animal animal=new Cat();
        animal.eat();
    }
}

解释1:以上这些代码这样是完全可以的,但是是private呢?



那么有什么办法可以让它继承呢?

可以的,可以有私有成员变量,只是不能直接获取。反射技术,暴力破解。

解释2:静态变量和方法可以继承,但是这个属于共享,不属于继承。因为这个东西是父类独有的,只有一份。

继承后成员变量的特点:

就近原则:子类继承父类以后,子类定义变量和父类重名,调用的时候先调子类的成员变量,要是子类没有或者不重名,则调用父类。或者可以使用this.xxx和super.xxx来区分。

继承后子类方法的特点:

就近原则:子类继承父类以后,调用方法的时候还是先调子类,后调父类,方法一样,优先使用子类已有的方法。

方法的重写

子类继承了父类,子类就得到了父类的某个方法。但是子类觉得这个方法不好或者无法满足自己的需求,子类就重写一个与父类声明一样的方法来覆盖父类的该方法,于是就进行方法的重写。

方法重写的校验注解 @Override

因为方法的重写的时候,如果方法名称写错,会调用父类的方法,引入@Override了之后,则不会有这种问题,可读性好,安全。

1.子类重写方法的形参列表与名称必须和父类一致。

2.子类重写方法的返回值类型声明要么和父类一致,要么比父类方法返回值类型范围更小。

3.子类重写方法的修饰符权限应该与父类被重写方法的修饰符权限相同或者更大。

总结:1.加注解

​ 2.声明不变,重新实现。

super访问父类方法

方法重写之后,还需要调用父类的方法,因此需要使用super,进行父类引用。



这样是不能直接调用,只可以在子类的方法中进行调用,使用实例方法调用实例方法的特点,就是做一个中转。

package com.itppf.super关键字;

public class Animal {
    public void eat(){
        System.out.println("父类方法!");
    }

}
package com.itppf.super关键字;

public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("子类重写方法!");
    }
    public void go(){
        super.eat();
    }
}
package com.itppf.super关键字;

public class Test {
    public static void main(String[] args) {
//       Animal animal=new Cat();
//        Cat cat=(Cat)animal;
//        cat.go();

        Cat cat=new Cat();
        cat.go();
        cat.eat();//重写过了
    }
}
注:注掉的是使用多态进行强转,父类强转为子类,向下转型,进行调用,eat()方法也可以是因为eat()被重写过了,这里的go方法相当于一个中转。
方法重写的拓展

1.私有方法可以被重写吗?不可以

继承后的构造器的特点

子类构造器的第一行首先是默认访问父类的无参构造器再访问自己的构造器,主要有个默认的super()方法。

package com.itppf.构造器;

public class Father {
    public Father(){ 
    super();        //调用父类的构造方法
        System.out.println("父类的构造器!");
    }
}
package com.itppf.构造器;

public class Son extends Father{
    public Son(){
    //这里默认有个super();
        System.out.println("子类的构造器");
    }
}
package com.itppf.构造器;
public class Test {
    public static void main(String[] args) {
        Son son=new Son();
    }
}

注:这里有一个重要的问题,子类构造器和父类构造器的问题。

作用:可以给父类构造方法传递实参,给父类中的字段赋值。 因为子类中创建该类的对象,可以给子类构造方法传递参数,在子类构造方法中调用父类带参数构造方法,可以给父类构造方法传参数,父类中对应带参数的构造方法,可以给内部的字段或方法传参数值。

为什么在新建子类时要先调用父类的构造器?

子类构造器会默认调用 父类的无参构造器,如果父类没有无参构造器,则需在子类构造器的第一行显式地调用父类的其他构造器。

其次,从继承的思想来看,你继承一个类,就相当于扩展一个类,形成一个更为特殊的类,但经常,我们需要将子类向上转型为基类,以便使用或达到其他各种目的。

这时,如果你生成子类对象时没有调用父类的构造器,那么,我们在使用父类的一些成员变量的时候,就会报变量未初始化的错误。请记住,变量初始化总是在构造器调用之前完成!

构造一个对象,先调用其构造方法,来初始化其成员函数和成员变量。子类拥有父的成员变量和成员方法,如果不调用,则从父类继承而来的成员变量和成员方法得不到正确的初始化。

举个例子:Animal(父类)
package com.itppf.构造器;

public class Animal {
    private String name;
    private String sex;
    private int age;
    public  Animal(){

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

    public  void  setName(String name){
        this.name=name;
    }
    public String getName(){
        return this.name;
    }
    public void  setSex(String sex){
        this.sex=sex;
    }
    public String getSex(){
        return this.sex;
    }
    public void setAge(int age){
        this.age=age;
    }
    public  int getAge(){
        return this.age;
    }

}

Cow类:

package com.itppf.构造器;

public class Cow extends Animal{
    public Cow(String name,String sex,int age){
      super(name,sex,age);  //根据参数匹配调用父类构造器,这里选择调用有参数的构造器,因为super()传参了。
    }
     public void eat(){
         System.out.println(getName()+"吃草");
     }
}

测试类:

package com.itppf.构造器;

public class Test2 {
    public static void main(String[] args) {
        Cow cow=new Cow("奶牛","雌",12);
    }
}

1.这里是 Cow cow=new Cow("奶牛","雌",12);---------------->

2.传递给Cow有参构造器进行初始化public Cow(String name,String sex,int age){...}而这里会默认调用父类的无参构造器,因为省略了super(),所以定义需要定义父类的无参构造器,其实不用调用也行,因为我们传递的是有参的构造器,但是为了规范还是新建了无参构造器。super(name,sex,age)---------------------->

3.将数据传递给父类的有参构造器。---------------------->

4.父类构造器使用this.name=name;赋值给this.name;

this关键字和super关键字

调用兄弟构造器,以上面的例子为例,假如我不想传递三个构造方法,只想让年龄这个参数默认为12。

那么我就要新建一个只含两个参数的兄弟构造器.

package com.itppf.this和super;

public class Animal {
    private String name;
    private  String sex;
    private  int age;

    public Animal(){

    }
    //鼠标左键+ctrl自动跳跃到下面构造器,这里传进来两个值,age默认为18
    public Animal(String name,String sex){
        this(name,sex,16);
    }
    public Animal(String name,String sex,int age){
        this.name=name;
        this.sex=sex;
        this.age=age;
    }

    public void setName(String name){
        this.name=name;
    }
    public String getName(){
        return this.name;
    }
    public void setSex(String sex){
        this.sex=sex;
    }
    public String getSex(){
        return this.sex;
    }
    public void setAge(int age){
        this.age=age;
    }
    public int getAge(){
        return this.age;
    }
}
package com.itppf.this和super;

public class Test {
    public static void main(String[] args) {
        //给构造方法传值
        Animal animal1=new Animal("小狗","雄",18);
        System.out.println(animal1.getName());
        System.out.println(animal1.getSex());
        System.out.println(animal1.getAge());
        System.out.println("*******************");
        //给构造器传两个值,让构造器调用兄弟构造器
        Animal animal2=new Animal("小猫","雌");
        System.out.println(animal2.getName());
        System.out.println(animal2.getSex());
        System.out.println(animal2.getAge());
    }
}
这里突然产生了一个问题,使用set传值和构造器传值有什么不同?

答:其实就是构造方法传值只是初始化,而使用set方法则是修改属性值。

继承的特点:
1.单继承:一个类只能继承一个直接父类。
2.多层继承:一个类可以间接继承多个父类。
为什么java是单继承?

设计层面的东西可以使用反证法。

3.一个类可以有多个子类
5.一个类默认继承了Object类,要么间接继承了Object类,Object是java的基类。

引用类型作为方法参数和返回值(对象的回调)

package com.itppf.对象的回调;

public class Cat {
    public void type(){
        System.out.println("你觉得它是什么品种的猫?");
    }
}
package com.itppf.对象的回调;
public class Test {
    public static void main(String[] args) {
        Cat fatcat=new Cat();
        answer(fatcat);
    }
    public static void answer(Cat cat){
        cat.type();
        System.out.println("这个品种的猫怎么样?");
    }
}

传递流程:new Cat()创建的地址存储在fatcat里面--------->fatcat会传到answer(fatcat);里面---------------->然后再传给answer(Cat cat)里面的cat。---------------->最后调用answer方法里面的type()方法。

引用类型作为成员变量

package com.itppf.引用类型作为成员变量;

public class Student {
    private String name;
    private String sex;
    private int age;
    private Address address;   //引用类型的变量
    //无参构造器
    public Student(){

    }
    //有参构造器,不过这里使用的是set方法传值
//    public Student(String name,String sex,int age){
//        this.name=name;
//        this.sex=sex;
//        this.age=age;
//    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

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

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}
package com.itppf.引用类型作为成员变量;

public class Address {
    private String name;
    private String code;
    private double x;
    private double y;
    //无参构造器
    public Address(){

    }
    //有参构造器
    public Address(String name,String code,double x,double y){
        this.name=name;
        this.code=code;
        this.x=x;
        this.y=y;

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public double getX() {
        return x;
    }

    public void setX(double x) {
        this.x = x;
    }

    public double getY() {
        return y;
    }

    public void setY(double y) {
        this.y = y;
    }
}
package com.itppf.引用类型作为成员变量;

public class Test {
    public static void main(String[] args) {
        Student s1=new Student();
        s1.setName("张三");
        s1.setSex("男");
        s1.setAge(12);
        System.out.println("姓名:"+s1.getName()+"\t性别:"+s1.getSex()+"\t年龄:"+s1.getAge());

        //这里使用构造器传递初始值
        Address address=new Address("北京","02020",150.0,120.0);
        //这里将刚刚new的地址实例传入到s1实例的地址信息中。
        s1.setAddress(address);
        //这里创建了一个地址实例,用来调用引用型变量Address的属性值。
        Address address1=s1.getAddress();
        System.out.println(address1.getName()+"\t"+address1.getCode()+"\t"+address1.getX()+"\t"+address1.getY());
    }
}

总结:以上就是我所学java进阶的第一阶段,这个阶段主要是对前面内容进行了一个深度的总结和升。

上一篇下一篇

猜你喜欢

热点阅读