JavaSE-面向对象

面向对象

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

初识面向对象

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

抽象

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

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

三大特性:

封装

继承

多态

方法回顾和加深

修饰符

返回值类型

可以为八大基本类型和引用类型,也可以为void(无返回值),返回值类型为void时,书写return;

return 与 break区别:

break:跳出switch,结束循环

return:结束方法

参数列表:参数类型+参数名 以及可变长参数

抛出异常:

 public void readFile(String file) throws IOException {
        
    }

方法的调用

主要分为有static修饰和无static修饰

当有static修饰符修饰的方法,是跟类一起加载的,即使类没有被实例化也可以直接调用。类名.方法名 调用该方法

当无static修饰符修饰的方法,是类实例话后才加载的,不可以直接调用,需要实例化类后通过类的实例化对象进行调用

//学生类
public void say(){
  System.out.println("学生说话了");
}
//另一个demo类  
public static void main(String[] args) {

  //对象类型  对象名  = 对象值
  student student = new student();
  student.say();

}

值传递和引用传递

先来看值传递

//值传递
public class Demo04 {
    public static void main(String[] args) {
        int a = 1;
        int b = 2;

        System.out.println(a);
        System.out.println(b);

        System.out.println("===================change===================");
        Demo04.change1(a);
        System.out.println(a);  //1,因为没有把change方法中的值返回出来,所以并没有发生变化
        b = Demo04.change2(b);
        System.out.println(b);

    }

    //返回值为空
    public static void change1(int a){
        a = 10;
    }
    public static int change2(int b){
        b = 20;
        return b;

    }

引用传递

//引用传递:一般是传递一个对象,本质还是值传递
//一个class里只能有一个public class,但可以有多个class
public class Demo05 {

    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.name); //null


        //这里不同于值传递,因为在change方法中传入的是person这个对象,修改的是person这个对象的.name属性,所以成功了,
        Demo05.change(person);
        System.out.println(person.name);

    }


    public static void change(Person person){
        person.name = "Zh1z3ven";
    }


}

//定义了一个person类,有一个属性:name
class Person{
    String name;    //null
}

this关键字

代表当前这个类或者对象

对象的创建分析

使用new关键字创建对象

在使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用。

类中的构造器也称为构造方法,是在进行创建对象的时候必须调用的。并且构造器有以下两个特点

1、必须和类的名字相同

2、必须没有返回类型,也不能写void

public class Student {

    //属性:字段
    String name;    //创建实例化对象时默认为null
    int age;    //0


    //方法
    public void study(){
        System.out.println(this.name + "is Learning...");
    }

}
public class Application {

    public static void main(String[] args) {
        //类是抽象的,需要实例化
        //类实例化后会返回一个自己的对象
        //stduent就是student类的具体实例

        Student xiaoming = new Student();
        Student agou = new Student();

        xiaoming.name = "小明";
        xiaoming.age = 18;

        System.out.println(xiaoming.name);
        System.out.println(xiaoming.age);


        agou.name = "阿狗";
        agou.age = 18;

        System.out.println(agou.name);
        System.out.println(agou.age);

    }

}

构造方法

1、和类名相同

2、没有返回值

3、new的本质是在调用构造方法

4、初始化对象的值

5、定义有参构造之后,如果想使用无参构造,需要显示的定义一个无参的构造,不然就只有有参构造方法

6、alt + insert 快捷键

public class Person {

    //一个类即使什么都写,他也会存在一个构造方法
    //构造方法用来初始化值
    /* 形如":
    public Person(){
    }
     */
    //显示定义构造方法
    String name;

    //使用new关键字必须有构造方法,本质是在调用构造方法
    //无参构造方法
    public Person(){
        //可以帮助我们初始化对象的属性值
        this.name = "Zh1z3ven";
    }

    //有参数构造:一旦定义了有参构造,无参构造方法必须显示定义
    //this.name代表Person类的属性name
    //后面的name为有参构造方法传递的String name参数
    //alt+insert生成构造方法
    public Person(String name){
        this.name = name;
    }

    public static void main(String[] args) {

        //new 实例化了一个对象
        Person person = new Person();

        System.out.println(person.name);

    }

}

创建对象内存分析

代码:

public class Pet {

    public String name;
    public int age;

    //无参构造
    

    public void shout(){
        System.out.println("叫了一声");
    }

}


public class Application {
    public static void main(String[] args) {

        Pet dog = new Pet();
        dog.name = "旺财";
        dog.age = 3;
        dog.shout();

        System.out.println(dog.name);
        System.out.println(dog.age);

    }
}

首先会现在方法区加载Application类(类中包括其main()方法,常量池(存放字符串;但int型数字不算在常量池内)),并在栈中加载main方法

image-20210611201748506

main方法在栈的最低下,方法的调用执行都在栈中执行。之后运行到Pet dog = new Pet()时,先会在方法区实例化对象所需的模版,即加载一个Pet类,包括该类的属性、常量池和非静态方法。之后当加载完后 讲赋值语句右边的new Pet()赋值给左边的Pet dog时,在栈中会加载一个dog的变量,dog变量暂时只是一个引用变量,引用在堆中生成的实例化对象,类似于指针,该引用指向该实例化对象在堆中的内存地址。

image-20210611202829021

而在实例化对象内的shout()是在引用方法区中Pet类中的shout()方法。之后执行到赋值语句时也就是

dog.name = "旺财";dog.age = 3;

这时会把Application类中的常量池中的旺财赋值给中的name ,之后3赋值给堆中的age ,同时shout()调用的是Pet类中的shout()方法(因为并没有参数传递,所以是同一个方法)

image-20210611203240461

在方法区中的静态方法区内,这里存放的是被static修饰符修饰的方法都会同类同时被加载,所以可以不用通过实例化对象就可以直接调用被static修饰的方法。

image-20210611203429557

简单小结类与对象

类是一个模版,是实例化对象的模版

对象是一个具体的实例,是一个类的实例化对象

方法的定义

修饰符 返回值类型 方法名(参数类型 参数名){
方法体
...
return 返回值;
}

方法的调用

调用方法:对象名.方法名(实参列表)

Java支持两种调用方法的方式,根据方法是否有返回值来选择。

return不仅可以返回值,同样可以结束这个方法。例:return 0;结束当前方法。

当方法返回一个值的时候,方法调用通常被当作一个值赋值给一个变量。

int larger = max(30, 40);

当方法返回值为void时,方法调用一定是一条语句

System.out.println("Hello, Zh1z3ven!");

对象的引用

引用类型:

基本类型8个(byte、short、int、long、float、double、boolean、char)

剩下的都是引用类型,对象也是通过引用来操作的:栈-->堆(地址)

属性:字段field 成员变量,默认初始化(数字:0,char:u000,boolean:false,引用:null)

属性的定义:

修饰符 属性类型 属性名 = 属性值

对象的创建和使用

必须使用new关键字创建对象 ,注意构造方法,Person zh1z3ven = new Person()

对象的属性: zh1z3ven.name

对象的方法: zh1z3ven.sleep()

静态的属性:属性

动态的行为:方法

面向对象三大特性

封装

程序设计追求“高内聚、低耦合”,高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。

属性私有 get/set

属性私有,即用private修饰属性

get/set,对外提供get set方法使得外部可通过该方法控制属性值

同时可在set方法中进行安全设置,提高程序的安全性

/*1、提高程序的安全性2、隐藏代码的实现细节3、统一接口 get、set形成规范4、提高系统可维护性 */public class Student {    //属性私有,加private关键字去修饰属性    private String name;    private int id;    private char sex;    private int age;    //提供一些可以操作这个属性的方法    //提供public的get或set方法    public String getName(){        return this.name;    }    public void setName(String name){        this.name = name;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public char getSex() {        return sex;    }    public void setSex(char sex) {        this.sex = sex;    }    public int getAge() {        return age;    }    public void setAge(int age) {        if (age > 120 || age < 0){            this.age = 3;        }else {            this.age = age;        }    }}public class Application {    public static void main(String[] args) {        Student s1 = new Student();        s1.setName("Zh1z3ven");        System.out.println(s1.getName());        //并不能通过形似s1.name直接访问操作类的属性,但是可以通过某些可被调用的外部方法去操作这个类的私有属性值        //封装:1、属性私有。2、提供可被外部调用的方法去操作私有属性        //alt+insert 选中getter and setter一键生成 get set方法,        //mac为control+return,选中所需要设置的属性即可直接生成        //或者右键选择generate    }}

继承

extends

继承的本质是对某一批类的抽象,从而实现对现实世界的更好的建模

Java中只有单继承没有多继承

继承就是扩展的意思,子类是对父类的扩展。

子类可以继承父类的所有方法

继承是类和类之间的一种关系,除此之外还有依赖,组合,聚合等

继承关系的俩个类,一个为子类(派生类)一个为父类(基类)。子类继承父类,使用关键字extends表示

子类和父类之间,从意义上讲因该具有 is a 的关系

Ctrl + h 可以看该类的继承关系

object类

在Java中所有的类都默认直接或间接继承于Object

super

如果父类重写了有参构造,最好也写上无参构造,以便后续子类去继承该父类(不然只能调用父类的有参构造方法,默认是调用无参的构造方法)

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

this代表本身调用者的这个对象

super代表父类对象的引用

super必须存在继承关系才可以使用

this(); 代表本类的构造方法

super(); 代表父类的构造方法

//父类public class Person {    public Person(){        System.out.println("Person无参执行了");    }    public int money = 1000000000;    public void say(){        System.out.println("说了一句话");    }    protected String name = "Zh1z3ven";    public void print(){        System.out.println("Person");    }}
//子类public class Student extends Person {    //默认调用了父类的无参构造,调用父类的构造方法必须在子类构造方法的第一行    public Student(){        super();        //也可以不写        System.out.println("Student无参执行了");    }    private String name = "zh1z3ven";    public void print(){        System.out.println("Student");    }    public void test1(){        print();        this.print();        super.print();    }    public void test(String name){        System.out.println(name);//传递的参数name        System.out.println(this.name);//student的属性name        System.out.println(super.name);//父类的属性name    }}
public class Application {    public static void main(String[] args) {        Student student = new Student();        student.test("zz");        student.test1();    }}

方法重写

重写都是非静态方法的重写(static方法属于类的方法,不属于实例的方法,重写指的是重写实例的方法)

final修饰的是常量池中的常量,不能被重写。private方法不能被重写。

子类重写方法的权限修饰符要大于父类 public>protected>default>private

方法名必须相同、参数列表必须相同(不然就是重载了)

抛出异常的范围与权限修饰符的范围一致

子类的方法与父类的方法必须要一致,但是方法体不同

为什么需要重写?

1.父类的功能,子类不一定需要,或者不一定满足

  1. alt+insert / control + return @override
@Override  //注解:有功能的注释    public void test() {        super.test();			//默认调用父类的方法,也可以自己重写    }

当重写一个非静态父类方法时,在子类中contorl + return即可生成一个重写方法

静态方法是属于类的方法,当下面test()方法为static修饰的静态方法时,那么会各自调用自己类中的test()方法。因为此时调用的是类中的静态方法;而当没有static修饰时,这时调用的都是A类中的test()方法,因为这时调用的是A的实例化对象加载的test()方法(只有static修饰的方法才会和类一起在方法区中同时加载)

可以简单理解为一旦子类重写了父类的方法,就执行子类的方法

class A extends BA a = new A();a.test();//父类引用指向子类B b = new A();b.test()A类中test()实现:System.out.println("A=>test()");B类中test()实现:System.out.println("B=>test()");

多态

class Student extends PersonStudent s1 = new Student();Person s2 = new Student();Object s3 = new Student();

一个对象的实际类型是确定的(new Student();),但是可以指向的引用类型就不确定了(Student s1/Person s2/Object s3

多态注意事项:

  • 多态是方法的多态,属性没有多态
  • 父类和子类有联系. ClassCastException类型转换异常
  • 多态存在的条件:继承关系、方法需要重写、父类的引用指向子类对象 Father f1 = new son();

Instanceof

判断一个对象是什么类型,可以判断两个类之间是否存在继承关系

    					//Object > String        //Object > Person > Student        //Object > Person > Teacher        Object object = new Student();     //Object类型        System.out.println(object instanceof Student);  //true        System.out.println(object instanceof Person);   //true        System.out.println(object instanceof Object);   //true        System.out.println(object instanceof Teacher);  //false        System.out.println(object instanceof String);   //false        System.out.println("===================================");        Person person = new Student();        System.out.println(person instanceof Object);    //true        System.out.println(person instanceof Person);    //true        System.out.println(person instanceof Student);    //true        System.out.println(person instanceof Teacher);      //false        //System.out.println(person instanceof String);    //编译报错    }

类型转换

public static void main(String[] args) {        //类型之间的转化:  父      子        //低 --> 高 可以自动转换                //高 --> 低 需要强制转换          Person obj = new Student();                //student将这个对象转换为Student类型,就可以使用Studen类型的方法        Student student = (Student) obj;	//强制转换        student.go();                ((Student) obj).go();							//强制转换        Person person = student;        //自动转化    }    

static关键字

static : 修饰成员变量或者方法,修饰为静态变量或者静态方法

被static修饰的属于类,非static的属于对象

静态变量属于类的变量,存储在方法区的静态方法区内,是一块固定的内存,随着类的加载同时加载,当直接使用类去调用一个变量说明此变量就是静态变量

非静态方法也可以直接调用静态方法

静态方法可以直接调用,无需实例化对象

//static : 修饰成员变量或者方法,修饰为静态变量或者静态方法//被static修饰的属于类,非static的属于对象public class Student {    //静态变量属于类的变量,存储在方法区的静态方法区内,是一块固定的内存,随着类的加载同时加载,当直接使用类去调用一个变量说明此变量就是静态变量    private static int age;     //静态变量    private double score;       //非静态变量    public void run(){        go();                   //非静态方法也可以直接调用静态方法    }    public static void go(){    }    public static void main(String[] args) {        Student s1 = new Student();        System.out.println(Student.age);        System.out.println(s1.age);        System.out.println(s1.score);        s1.run();        Student.go();   //静态方法可以直接调用,无需实例化对象        go();    }}
public static void main(String[] args) {        Student student = new Student();        System.out.println("==================");        Student student1 = new Student();    }    // 2    :赋初始值    {        System.out.println("匿名代码块");        //匿名代码块        //随着对象的创建而创建,在构造方法之前    }    // 1    :   只执行一次,后面不会执行    static {        //静态代码快,方便加载初始化一些数据        //随着类的加载而加载,永久只执行一次        System.out.println("静态代码快");    }    // 3    //alt+inset/contorl+return --> select none    public Student() {        System.out.println("构造方法");    }}输出结果:静态代码快匿名代码块构造方法==================匿名代码块构造方法

利用static静态导入包及常量

//静态导入包import static java.lang.Math.random;import static java.lang.Math.PI;

抽象类和接口

抽象类

abstract修饰符可以修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,该类就是抽象类

抽象类中可以没有抽象方法,但是抽象方法的类一定要声明为抽象类

抽象类,不能使用new关键字来创建对象,它是用来让子类继承的(类是单继承)

抽象方法,只有方法的声明,没有方法的实现,它是用来让子类方法去实现的

子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类

public  abstract class Action {    //抽象方法,只有方法名字,没有方法的实现    public abstract void doSomething();    //抽象类不能new,只能靠子类去实现    //抽象类可以写普通方法    //抽象类存在构造方法吗?    //抽象类存在的意义?提高开发的可扩展性}//继承抽象类的子类必须重写抽象方法并实现,除非子类也是abstractpublic class A extends Action{    @Override    public void doSomething() {    }}

接口

声明接口的关键字是interface

接口可以多继承

普通类:只有具体的实现

抽象类:具体实现和规范(抽象方法)都有

接口:只有规范。约束和实现分离(面向接口编程)

接口就是规范,定义的是一组规则,体现了现实世界中“如果你是。。。你必须能。。”的思想。如果你是天使你必须能飞,如果你是汽车,你必须能跑。

接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。

OO的精髓,是对对象的抽象,最能体现这一点的就是接口。

//interface 定义的关键字public interface UserService {    //接口中的所有定义其实都是抽象的,不能在接口中实现方法    //修饰符默认为 public abstract    //常量。默认修饰符为 public static final    int AGE = 99;    void add(String name);    void delete(String name);    void update(String name);    void select(String name);}
//实现接口需要重写里面的方法,类可以实现接口//public class 类名(一般以Impl结尾) implements 接口名//接口可以多继承public class UserServiceImpl implements UserService, TimeService{    @Override    public void add(String name) {    }    @Override    public void delete(String name) {    }    @Override    public void update(String name) {    }    @Override    public void select(String name) {    }    @Override    public void timer() {    }}
public interface TimeService {    void timer();}

接口小结

  • 接口是一种规范、约束
  • 只有方法的定义,没有方法的实现
  • 方法默认修饰符为public abstract
  • 常量默认修饰符为public static final
  • 接口不能被实例话,接口没有构造方法
  • implements可以实现多个接口
  • 继承接口的类必须重写实现接口的方法

内部类

内部类主要分为四种:成员内部类、局部内部类、静态内部类、匿名内部类

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

成员内部类

public class Outer {    private int id = 10;    public void out(){        System.out.println("这是外部类的方法");    }    public class Inner{        public void in(){            System.out.println("这是内部类的方法");        }        //内部类访问外部私有变量        public void getID(){            System.out.println(id);        }    }}
public static void main(String[] args) {        Outer outer = new Outer();        outer.out();        //通过外部类实例话内部类:成员内部类        Outer.Inner inner = outer.new Inner();        inner.in();        inner.getID();            }

静态内部类

静态内部类无法直接访问外部类的非静态属性

public class Outer {    private int id = 10;    public void out(){        System.out.println("这是外部类的方法");    }    public static class Inner{        public void in(){            System.out.println("这是内部类的方法");        }        //内部类访问外部私有变量        public void getID(){            System.out.println(id);        }    }}

还可以在java文件中声明另一个类

public class Outer {    private int id = 10;    public void out(){        System.out.println("这是外部类的方法");    }    public class Inner{        public void in(){            System.out.println("这是内部类的方法");        }        //内部类访问外部私有变量        public void getID(){            System.out.println(id);        }    }}//一个java文件里面只能有一个public class,但是可以有多个classclass A{    }

局部内部类

在类的方法中创建一个类

public class Outer {    public void method(){            //局部内部类        class Inner{                    }    }}

匿名内部类

没有类名的内部类

public class Test {    public static void main(String[] args) {        //没有名字初始化类        //匿名对象的使用,不用把实例保存在变量中       new Apple().eat();             UserService userService = new UserService(){           @Override           public void hello() {                          }       };            }    }class Apple{    public void eat(){        System.out.println("1");    }}interface UserService{    void hello();}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章