Java面向对象

Java面向对象

break和return的区别

return 语句的作用

1.return 从当前的方法中退出,返回到该调用的方法的语句处,继续执行。

2.return 返回一个值给调用该方法的语句,返回值的数据类型必须与方法的声明中的返回值的类型一致。

3.return后面也可以不带参数,不带参数就是返回空,其实主要目的就是用于想中断函数执行,返回调用函数处。(返回值为void的方法,从某个判断中跳出,必须用return.)

break语句的作用

1.break在循环体内,强行结束循环的执行,也就是结束整个循环过程,不在判断执行循环的条件是否成立,直接转向循环语句下面的语句。

2.当break出现在循环体中的switch语句体内时,其作用只是跳出该switch语句体。

面向对象编程

面向过程&面向对象

  • 面向过程思想
    • 步骤清晰简单,第一步做什么,第二步做什么...
    • 面对过程适合处理一些较为简单的问题
  • 面向对象思想
    • 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。
    • 面向对象适合处理复杂的问题,适合处理需要多人协作的问题!
  • 对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。

什么是面向对象

  • 面向对象编程(OOP:Object-Oriented Programming)

  • 面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据。

  • 从认识论角度考虑是先有对象后有类。对象,是具体的事物。类,是抽象的,是对对象的抽象

  • 从代码运行角度考虑是先有类后有对象。类是对象的模板。

类与对象的关系

  • 类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物

    • 例如:动物、植物、手机、电脑..…
    • Person类、Pet类、Car类等,这些类都是用来描述/定义某一类具体的事物应该具备的特点和行为
  • 对象是抽象概念的具体实例

    • 张三就是人的一个具体实例,张三家里的旺财就是狗的一个具体实例,
    • 能够体现出特点,展现出功能的是具体的实例,而不是一个抽象的概念.

创建与初始化对象

使用new关键字创建对象

  • 使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用。
  • 类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有以下俩个特点:
    • 1.必须和类的名字相同
    • 2.必须没有返回类型,也不能写void
//一个类即使什么都不写,它也会存在一个无参构造
public class Person {
    String name;
    int age;

    //无参构造
    public Person(){}

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

    public static void main(String[] args) {
        Person person1 = new Person();//调用无参构造方法
        Person person2 = new Person("小明",18);//调用有参构造方法

        System.out.println(person1.name);//输出null
        System.out.println(person2.name);//输出小明
    }

    /*
     * 构造器(构造方法):方法名必须和类名相同且没有返回值
     * 作用:1.new本质在调用构造方法  2.初始化对象的值
     * 注意点:如果在类定义了有参构造,必须显式定义无参构造
     */
}

创建对象内存分析

封装

  • 封装(数据的隐藏)

    • 该露的露,该藏的藏。我们程序设计要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。
    • 通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
  • 例:属性的私有,get/set

    • Person类
    public class Person {
        //属性私有
        private String name;
        private int age;
        private char sex;
    
        //通过提供public的get和set方法让外部操作这些属性
        //通过get方法获取这些属性
        public String getName(){
            return this.name;
        }
        //通过set方法给这个属性设置值
        public void setName(String name){
            this.name = name;
        }
    
        public char getSex(){
            return this.sex;
        }
    
        public void setSex(char sex){
            this.sex = sex;
        }
    
        public int getAge(){
            return this.age;
        }
    
        //可以在方法里面设置一些判断来规避数据的不合法
        public void setAge(int age){
            if(age>130||age<0){
                System.out.println("年龄不合法");
            }else {
                this.age = age;
            }
        }
    }
    
    • Test测试类
    public class Test {
        public static void main(String[] args) {
            Person person = new Person();
            //System.out.println(person.name); 报错,因为Person通过private把属性私有化,无法直接获取对象,只能通过get方法获取
            person.setName("小明");
            person.setSex('男');
            person.setAge(999);
            System.out.println(person.getName()+" "+person.getAge()+" "+person.getSex());
        }
    }
    
  • 封装的好处:

    • 提高程序的安全性,保护数据
    • 隐藏代码的实现细节
    • 统一接口
    • 系统的可维护性增加

继承

  • 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
  • extends的意思是“扩展”。子类是父类的扩展。
  • JAVA中类只有单继承,没有多继承!每个子类只能有一个父类,但一个父类可以有多个子类(一个儿子只能有一个爸爸,但是一个爸爸可以有多个儿子)
  • 继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
  • 继承关系的俩个类,一个为子类(派生类).一个为父类(基类)。子类继承父类,使用关键字extends来表示。
  • 子类和父类之间,从意义上讲应该具有"is a"的关系.

示例:Person类作为父类,分别由Student和Teacher继承

1.Person类

public class Person {

    private int money = 10_0000_0000;

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    public void say(){
        System.out.println("这是在Person类创建的say方法");
    }
}

2.Student类

//子类继承了父类,就会拥有父类的全部方法和属性(前提是父类未加private私有化的情况下)
public class Student extends Person{}

3.Teacher类

public class Teacher extends Student{}

4.测试类Test

public class Test {
    public static void main(String[] args) {
        Student student = new Student();
        student.say();//输出:这是在Person类创建的say方法
        System.out.println(student.getMoney());//输出1000000000

        Teacher teacher = new Teacher();
        teacher.say();//输出:这是在Person类创建的say方法
        System.out.println(teacher.getMoney());//输出1000000000
    }
}

在idea使用Ctrl+H查看层次结构,可以看到:在Java中,所有的类,都默认直接或者间接继承Object类

Java Object 类是所有类的父类,也就是说 Java 的所有类都继承了 Object,子类可以使用 Object 的所有方法

继承的特性

  • 子类拥有父类非 private 的属性、方法。
  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
  • 子类可以用自己的方式实现父类的方法。
  • Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
  • 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。

super和this关键字

例:在父类和子类分别定义同一名字的方法和属性

1.Person类(父类)

public class Person {
    protected String name = "Person";

	//如果方法名或者属性用private修饰,则无法被子类继承
    public void print(){
        System.out.println("Person");
    }
}

2.Student(子类)

public class Student extends Person{
    private String name = "Student";

    public void print(){
        System.out.println("Student");
    }
    
    //对比方法
    public void test1(){
        print();//输出Student
        this.print();//输出Student
        super.print();//输出Person
    }

    //对比属性
    public void test2(String name){
        System.out.println(name);//输出参数值
        System.out.println(this.name);//输出Student
        System.out.println(super.name);//输出Person
    }
}

3.Test测试类

public class Test {
    public static void main(String[] args) {
        Student student = new Student();
        student.test2("小王");
        student.test1();
    }
}

通过以上可以看出:

super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。

this关键字:指向本身这个类的引用。

例:再通过子类和父类的构造器对比

  • 父类Person

  • 子类Student

  • 通过测试类实例化Student执行结果:

通过执行结果可以看出:调用子类的构造器,子类的构造器也会隐式的调用父类的构造器

子类是不继承父类的构造器(构造方法或者构造函数)的,它只是调用(隐式或显式)。

如果父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。

super注意点:

  1. super调用父类的构造方法,必须在构造方法的第一个
  2. super 必须只能出现在子类的方法或者构造方法中!
  3. super和 this不能同时调用构造方法!

super和this的区别:

  • 代表的对象不同:
    • this:本身调用者这个对象
    • super:代表父类对象的应用
  • 条件不同:
    • this:没有继承也可以使用
    • super:只能在继承条件才可以使用

方法的重写

例1:创建一个父类B和子类A并在两个类里面写一个静态static的test方法

例2:把static静态修饰去掉再运行

由例1和例2可以看出:

  • 静态方法中,方法的调用只和左边定义的数据类型有关,即b是A new出来的对象,因此调用了A的方法,因为静态方法是类的方法,而非静态是对象的方法,有static时,b调用了B类的方法,因为b是用B类定义的,没有static时,b调用的是对象的方法,而b是用A类new的

但只有方法不加static才算是重写!!!不加static才算是重写!!!不加static才算是重写!!!

方法重写的规则

  • 参数列表与被重写方法的参数列表必须完全相同。
  • 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。
  • 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。(访问权限:public > protected > default > private)
  • 父类的成员方法只能被它的子类重写。
  • 声明为 final 的方法不能被重写。
  • 声明为 static 的方法不能被重写,但是能够被再次声明。
  • 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
  • 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
  • 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
  • 构造方法不能被重写。
  • 如果不能继承一个类,则不能重写该类的方法。
  • 重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。(例:父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,只能抛出 IOException 的子类异常。)

(参考来自菜鸟教程:https://www.runoob.com/java/java-override-overload.html)

多态

多态即同一方法可以根据发送对象的不同而采用多种不同的行为方式。

一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多

多态存在的条件:

  • 继承关系
  • 子类重写父类方法
  • 父类引用指向子类对象

例:

1.父类

public class A{
    public void run(){
        System.out.println("父类run方法");
    }
}

2.子类

public class B extends A{
    @Override
    public void run() {
        System.out.println("子类重写的run方法");
    }

    public void eat(){
        System.out.println("子类独有的方法");
    }
}

3.测试

public class Test {
    public static void main(String[] args) {
        //一个对象的实际类型是确定的 例:new A();   new B();

        //可以指向的引用类型就不确定了:父类的引用可以指向子类
        //子类能调用的方法都是自己本身或者继承父类的方法
        B b = new B();
        A a = new B();

        b.run();//输出:子类重写的run方法
        a.run();//输出:子类重写的run方法
        
        //a.eat(); //父类型可以指向子类,但无法调用子类独有的方法,只能通过向下转型调用:((B) a).eat();

    }
}

多态的注意事项:

  • 多态是方法的多态,属性是没有多态的
  • 多态必须是子类和父类之间的联系
  • 如果有静态(static),常量(final),私有化(private)修饰的话是无法进行多态化的

Static关键字

在《Java编程思想》P86页有这样一段话:

“static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。”

这段话虽然只是说明了static方法的特殊之处,但是可以看出static关键字的基本作用,简而言之,一句话来描述就是:

方便在没有创建对象的情况下来进行调用(方法/变量)。

很显然,被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。

​ static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能。

  • static变量
    • static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
    • static成员变量的初始化顺序按照定义的顺序进行初始化。
public class Person {
    private static int age;//静态变量
    private double score;//非静态变量

    public static void main(String[] args) {
        //静态变量随着类加载就可以通过类名进行访问
        System.out.println(Person.age);
        
        //非静态变量无法随着类加载,需要创建对象初始化时,通过对象去调用
        System.out.println(Person.score);//报错:Non-static field 'score' cannot be referenced from a static context

        Person p1 = new Person();
        System.out.println(p1.score);
        System.out.println(p1.age);
    }
}
  • static方法
    • static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。(但是要注意的是,虽然在静态方法中不能访问非静态成员方法和非静态成员变量,但是在非静态成员方法中是可以访问静态成员方法/变量的)
public class Person {
    //非静态方法
    public void run(){
        go();//在非静态成员方法中是可以访问静态成员方法或变量的
    }

    //静态方法
    public static void go(){}

    public static void main(String[] args) {
        go();
        run();//报错:Non-static method 'run(' cannot be referenced from a static context
    }
}
  • static代码块
    • static关键字还有一个比较关键的作用:用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次
public class Person {
    //静态代码块只执行一次
    static{
        System.out.println("静态代码块");
    }

    {
        System.out.println("匿名代码块");
    }

    public Person(){
        System.out.println("构造方法");
    }

    public static void main(String[] args) {
        Person p1 = new Person();
        System.out.println("=======================");
        Person p2 = new Person();
    }
}

以上摘自其他文章,详情请查看:http://www.cnblogs.com/dolphin0520/p/3799052.html

抽象类

  • abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么该类就是抽象类。
  • 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类。
  • 抽象类:不能使用new关键字来创建对象,它是用来让子类继承的。
  • 抽象方法:只有方法的声明,没有方法的实现,它是用来让子类实现的。
  • 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。
//abstract:抽象的
public abstract class Person {

    //抽象方法,只有方法的名字,没有方法的实现
    public abstract void doSomeThing();

    /*
     * 1.抽象类不能实例化(new),只能靠子类去实现它
     * 2.抽象方法中也可以写普通方法
     * 3.如果一个类定义了抽象方法,则这个类也必须通过abstract修饰为抽象类
     * 4.抽象类中也存在构造器,但不可以创建抽象类的实例,所以构造函数只能通过构造函数链调用
     */
}

内部类

内部类就是在一个类的内部在定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类了。

  • 成员内部类

    • 内部类与外部类可以方便的访问彼此的私有域(包括私有方法、私有属性)。

    • 内部类是另外一种封装,对外部的其他类隐藏。

    • 内部类可以实现java的单继承的局限性。

  • 静态内部类

    • Java中的静态内部类:在定义的内部类前加static修饰符,此时的内部类就是静态内部类
    public class Outer {
        //定义一个外部类的实例变量a和静态变量b
        private int a;
        private static int b;
    
        //定义一个静态方法和一个非静态方法
        public static void say(){}
        public void test(){
            Outer.Inner.c = 1; //可以通过静态内部类的全类名来调用静态内部类的静态属性(外部类名.静态内部类名.属性)
    
            Outer.Inner.go(); //可以通过静态内部类的全类名来调用静态内部类的静态方法(外部类名.静态内部类名.方法)
    
            //Outer.Inner.walk(); //不能通过类静态内部类的全类名来调用内部类的非静态属性和方法
            Inner inner = new Inner();
            inner.d = 1;
            inner.walk(); //可以通过创建内部类实例来调用静态内部类的非静态属性和方法
        }
    
        //静态内部类
        public static class Inner{
            //在静态内部类定义一个静态变量c和一个实例变量d
            static int c;
            int d;
    
            //定义一个静态方法和一个非静态方法
            public static void go(){}
            public void walk(){
                //在静态内部类中可以调用外部类的静态属性和静态方法
                int f = b;
                say();
    
                //int e = a; 无法直接调用非静态属性
                //test();   无法直接调用非静态方法
    
                //但可以外部类实例化来调用非静态属性和方法4
                Outer outer = new Outer();
                int e = outer.a;
                outer.test();
            }
        }
    }
    

    总结:1、静态内部类中可以写哪些内容

       1)匿名代码块

       2)静态代码块

       3)静态变量和非静态变量

       4)静态方法和非静态方法

    注意:不能在静态内部类中写抽象方法

       2、外部类如何调用静态内部类中的属性和方法

       1)外部类可以通过创建静态内部类实例的方法来调用静态内部类的非静态属性和方法

       2)外部类可以直接通过“ 外部类.内部类.属性(方法)” 的方式直接调用静态内部类中的静态属性和方法

       3、静态内部类如何调用外部类的属性和方法 

       1)静态内部类可以直接调用外部类的静态属性和方法

       2)静态内部类可以通过创建外部类实例的方法调用外部类的非静态属性和方法

       4、如何创建静态内部类实例

       1)在非外部类中:外部类名.内部类名 name = new 外部类名.内部类名();

       2)在外部类中:内部类名 name = new 内部类名();

    注:以上静态内部类摘自作者:HEAVEN_1

posted @ 2021-07-28 22:34  Prpr君  阅读(68)  评论(0)    收藏  举报