小言_互联网的博客

Java面向对象编程

238人阅读  评论(0)

视频教程链接


1. 面向过程 & 面向对象


宏观方面需要面向对象的思想,但是微观就要使用面向过程的思想。


2. 什么是面向对象


java面向对象编程(oop)

面向对象特征:


3. 知识回顾 静态方法与非静态方法

修饰符 : static
静态方法:使用static修饰符

类可以直接调用另外一个类中的静态方法

非静态对象:

要 new 其他的类后才能使用其中的非静态方法。

在同个类中,不同的静态方法能互相调用,不同的非静态方法也能互相调用,非静态方法可以调用类中的静态方法,但是静态方法不能调用类中的非静态方法,因为二者的加载机制不同,static修饰的静态方法是和当前的类同时加载,非静态方法不是和类同时加载,静态方法相比非静态方法加载的时间要靠前一些。(听了狂神老师的课,这仅是个人理解,后面继续学习会补充这方面的知识)

非静态方法互相调用:

静态方法互相调用:

静态方法调用非静态方法:

非静态方法调用静态方法:


4. 值传递 引用传递

值传递:

//值传递
public class Demo03 {
   
    public static void main(String[] args) {
   
        
        int a = 1;
        System.out.println(a);
        Demo03.change(a);
        
        System.out.println(a);

    }

    public static void change(int a) {
   
        a = 10;
    }
}

结果:

发现第二次输出 a 的值并没有发生改变,可见当使用值传递向 change 函数传递变量 a 时,**只是传递了 a 的值。**所以实际参数 a 的值没有改变。

引用传递:

//引用传递
public class Demo04 {
   
    public static void main(String[] args) {
   
        Person person = new Person();
        System.out.println(person.name);

        Demo04.change(person);
        System.out.println(person.name);

    }
    public static void change(Person person) {
   
        person.name = "zqy";
    }
    //定义了一个Person类,有个name属性
    static class Person {
   
        String name;
    }
}

运行结果:

change 函数中传递的参数是 Person 并且该函数修改了 Person 函数中的属性 name。


5. 类与对象的关系



6. 创建与初始化对象

使用 new 创建对象

public class Application {
   
    //一个项目应该只有一个main方法
    public static void main(String[] args) {
   

        //使用 new 对抽象的类进行实例化
        Student zns = new Student();
        Student zqy = new Student();

        zns.name="伞兵1号";
        zns.age=1;
        System.out.println(zns.name);
        System.out.println(zns.age);
        zqy.name="伞兵2号";
        zqy.age=2;
        System.out.println(zqy.name);
        System.out.println(zqy.age);
    }
}
//学生类
public class Student {
   
    //属性,字段
    String name;
    int age;

    //方法
    public void study() {
   
        System.out.println(this.name + "在学习!!");
    }
}

7. 构造器


先写个方法,里面啥也不加:

public class Person {
   
}

使用另外一个启动类的main方法实例化并启动:

public class Application {
   

    public static void main(String[] args) {
   

        //使用 new 对抽象的类进行实例化
        Person person = new Person();
    }
}

发现成功运行,没有报错。
查看Person的编译文件:

和java文件对比,发现被自动添加了一个方法,这个方法就是构造方法。

也可以手动写显示构造器:(无参构造器)

public class Person {
   
    public  Person(){
   
        
    }
}

构造器作用

1.实例化初始值(为变量进行初始化)

public class Person {
   
    String name;

    public Person() {
   
        this.name = "zqy";
    }
}

2.使用 new 时,本质是去自动调用类中的构造器

注意:如果定义了有参构造,就一定要写显示构造器(否则会报错):

写了显示构造后:

idea 生成构造器快捷键 alt+ins

构造器重载:


8. 创建对象简单内存分析

Application类:

public class Application {
   
    public static void main(String[] args) {
   
        Pet dog = new Pet();
        dog.name = "旺财";
        dog.age = 3;
        System.out.println(dog.name);
        System.out.println(dog.age);


        Pet cat = new Pet();
        

    }
}

Pet类:

public class Pet {
   

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

1.当使用 new 去实例化一个对象时,先经过方法内的无参构造
2.加载类,加载类中的main方法、常量
3.执行main方法,将main方法压入到栈中(main方法是最先被压入栈的,所以说,当栈中的main方法被释放后,就可以认为这个方法已经结束)

4.加载 new 的类(实例化),加载被实例化类的属性和方法(类似于加载这个类,并把它当做模板,通过这个模板生成一个对象)
例:当 new 一个dog时,第一步,在堆中分配各 new 的这个方法一块内存并分配地址,将模板存入这个内存,第二步,将dog压入栈,并指向堆中分配的内存块

5.进行赋值时,堆中的变量直接引用方法中传入的值。由于shout( ) 没有参数,所以直接调用Pet类中的方法。

6.当又new了一个cat,同样,先在栈内分配内存获取地址,并且存入模板。栈内压入cat。并指向堆内的新分配的堆内存。

总体:


9. 封装

主要思想:

关键字: privatepublic对应
私有化的属性不能直接通过实例化后的方法进行访问,需要使用get和set方法。

使用get和set
idea 自动生成get、set方法(快捷键 alt+ins):

set方法,给这个变量赋值,get方法获取到这个变量的值

//private 属性私有
public class Student {
   

    private String name;
    private int id;

    //需要提供一些可以操纵这些属性的方法 get/set

    public String getName() {
   
        return name;
    }

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

    public int getId() {
   
        return id;
    }

    public void setId(int id) {
   
        this.id = id;
    }
}
public class Application {
   
    public static void main(String[] args) {
   

        Student s1 = new Student();
        s1.setName("马牛逼");
        System.out.println(s1.getName());

    }
}

结果:

通过 get set 方法能够对数据进行过滤:

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

        Student s1 = new Student();

        s1.setAge(500);
        System.out.println(s1.getAge());

    }
}
public class Student {
   

    private int age;

    public int getAge() {
   
        return age;
    }

    public void setAge(int age) {
   
        if (age > 120 || age < 0) {
   
            this.age = 3;
        } else {
   
            this.age = age;
        }
    }
}

封装的意义:

  1. 提高安全性,可以保护数据
  2. 隐藏代码的细节
  3. 统一接口
  4. 提高系统的可维护性

10. 继承

public class Person {
   
    //人
}
public class Teacher extends Person{
   
}
public class Student extends Person{
   
}

Person是父类(基类),其他两个Student和Teacher是子类(也可以叫派生类)

被final修饰的方法不能被继承(final之后断子绝孙了)

查看类继承树状图:
idea快捷键 ctrl + H

注意:所有的类都默认继承了Object类


11. Super详解

this关键字是一对,this代表当前的类,super代表父类

访问父类变量:

代码:

public class Person{
   
    protected String name = "zqy1";
}
public class Student extends Person {
   
    private String name = "zqy2";

    public void say(String name) {
   
        System.out.println(name);
        System.out.println(this.name);//访问自身属性
        System.out.println(super.name);//访问父类属性
    }

}
public class Application {
   
    public static void main(String[] args) {
   
        Student student1 = new Student();
        student1.say("zqy3");
    }
}

访问父类方法:

代码:

public class Person{
   
  public void print(){
   
      System.out.println("我是父类");
  }
}
public class Student extends Person {
   

    public void print() {
   
        System.out.println("我是子类");
    }

    public void test() {
   
        print();
        this.print();
        super.print();
    }
}
public class Application {
   
    public static void main(String[] args) {
   
        Student student1 = new Student();
        student1.test();
    }
}

注意:私有属性(private)无法被继承。

子类默认调用了父类的无参构造
例:

super( ); 默认隐性使用,如果要显性使用,就必须要在子类的第一行。

同样当使用this( );调用本类的构造参数时,也要在第一行。

啊这。。。。遇见问题了:这该如何是好


太菜了没见过。。。。。。

当使用super( ) ;调用有参构造时,要传入参数:

写完有参就没有无参了


12. 方法重写

重写是方法的重写,与属性无关。
只有非静态方法才能重写。

public class B {
   
     public  void test(){
   
        System.out.println("B");
    }
}
public class A extends B{
   

     @Override
    public void test() {
   
       //在这里重写父类的 test()方法
        System.out.println("我很牛");
    }
}

执行结果:

当使用static静态方法时:

小结:当使用static修饰方法时,方法调用只与new方法左边的有关,例如上图,分别使用B和A去new一个A方法,并调用其中的test()方法,结果是分别调用了属于左边类的方法(A调用了A中的test,B调用了B中的test)并没有进行重写操作。当不使用static修饰后,才会进行方法重写。(要进行重写的方法的修饰符必须为public)



13. 什么是多态


例:

public class Student extends Person {
   
//子类
}
public class Person{
   
//父类
}
public class Application {
   
    public static void main(String[] args) {
   

        //一个对象的实际类型是确认的(Student对应Student,Person对应Person)
        Student s1 = new Student();
        Person p1 = new Person();

        //可以指向的引用对象类型就不确定了:父类引用指向子类
   		Student s2 = new Student();
        Person s3 = new Student();
        Object p2 = new Person();
    }
}

同时调用一个方法,如果子类没有重写,就调用父类中该方法,如果子类进行重写,就调用子类重写后的方法。



例2:
代码:

public class Person {
   
    public void run() {
   
        System.out.println("父");
    }
}
public class Student extends Person {
   
    @Override
    public void run() {
   
        System.out.println("子");
    }

    public void eat() {
   
        System.out.println("吃");
    }
}
public class Application {
   
    public static void main(String[] args) {
   


        //Student可以调用的方法:自己独有的或者继承的方法
        Student s2 = new Student();
        //Person 父类型:可以指向子类,但不能调用子类独有的方法
        Person s3 = new Student();
        Object p2 = new Person();


        //对象能执行哪些方法,主要看等于号左边的类型,和右边的关系不大
        s2.eat();
        
        //父类型不能直接调用子类特有的方法,如果要调用,要进行强制类型转换
        s3.eat();
        ((Student) s3).eat();

        //子类重写了父类的方法,所以当父类调用这个被重写的方法是直接调用自子类重写后的方法
        s2.run();
        s3.run();
    }
}

运行结果:

小结:(staticfinalprivate修饰的方法不能被重写)

再次强调:只有方法有多态,属性没有多态。

多态教学视频


14. instanceof关键字

用来判断两个类之间是否存在父子关系(继承关系)

例:

public class Student extends Person {
   
    //子类
}
public class Teacher extends Person{
   
    //子类
}
public class Person{
   
//父类
}
public class Application {
   
    public static void main(String[] args) {
   

        /*
        继承关系
        Object > String
        Object > Person > Teacher
        Object > Person > Student
        */

        Object o1 = new Student();
        System.out.println(o1 instanceof Student);
        System.out.println(o1 instanceof Person);
        System.out.println(o1 instanceof Object);
        System.out.println(o1 instanceof Teacher);
        System.out.println(o1 instanceof String);

        Person p1= new Student();
        System.out.println(p1 instanceof Student);
        System.out.println(p1 instanceof Teacher);
        System.out.println(p1 instanceof Object);
//        System.out.println(p1 instanceof String);//编译报错
    }
}

总结公式:
X instanceof Y,当X和Y之间存在继承关系则该关系式的值为true。

类型转换

与变量类型转换原理相同,父类向子类转换(高 --> 低)需要强制类型转换,可能会导致子类的一些方法丢失,反之则不需要。

public class Student extends Person {
   
    //子类
    public void go(){
   
        System.out.println("go");
    }
}
public class Application {
   
    public static void main(String[] args) {
   


        Person s1 = new Student();
        //s1类型为Person,是Student的父类,所以,当s1要调用子类Student中的go方法时,要进行强制类型转换
        ((Student) s1).go();


        //子类转化为父类,低-->高 直接转化
        Student s2 = new Student();
        s2.go();
        Person p1 = s2;
    }
}

小结:


15.static关键字

1. 可以使用类名直接访问static修饰的变量(静态变量)

public class Student {
   
 	private static int age;//静态变量
    private double money;//非静态变量

    public static void main(String[] args) {
   
        Student s1 = new Student();

        System.out.println(Student.age);
        System.out.println(s1.age);
        System.out.println(s1.money);
    }
}

不能通过类名访问非静态变量

同样,静态方法也可以这么调用:

public class Student {
   


    public void run() {
   //非静态方法
    }

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


    public static void main(String[] args) {
   
        new Student().run();
        Student.go();
        go();//还可以直接调(因为是在当前的类中)
    }
}


静态方法能调用静态方法,非静态方法可以调用静态方法和非静态方法

2. 代码块

public class Person {
   

    {
   
        //匿名代码块
    }

    static {
   
        //静态代码块
        //和类同时加载,只生效一次
    }
}

代码块、静态代码块、构造方法三者的加载顺序:

public class Person {
   

    //第二执行
    {
   
        //匿名代码块
        System.out.println("匿名代码块");
    }

    //最先执行
    static {
   
        //静态代码块
        //和类同时加载,只生效一次
        System.out.println("静态代码块");
    }

    //最后执行
    public Person() {
   
        System.out.println("构造方法");
    }

    public static void main(String[] args) {
   
        new Person();
    }
}

再次new一个Person:


静态代码块只执行了一次

静态代码块的作用
赋初始值

3.静态导入包

例:
当我们要使用java封装好的方法时(以随机数生成为例)

需要输入 Math.random();非常的麻烦,
我们可以通过import直接导入Math包的random:

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

public class Test {
   

    public static void main(String[] args) {
   
        System.out.println(random());
    }
}

但是这种方法不怎么用…


16. 抽象类


写一个抽象类:

//abstract 修饰抽象类
public abstract class Action {
   

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

子类如果继承抽象类,就必须重写里面的方法:

//抽象类的所有方法必须要由子类实现(重写)
public class A extends Action{
   
    @Override
    public void doSomthing() {
   
        
    }
}

如果继承抽象方法的子类也是一个抽象方法,就不需要重写里面的方法,就会让一个不是抽象方法的子类(或者子类的子类)去重写


小结:

抽象类提高开发效率,将一些常用的变量进行抽象类封装

再看看抽象类有没有构造方法:

这个还真有。


17. 接口

//通过interface关键字定义接口
public interface UserServer {
   
    
    //接口中的所有定义都是抽象的 默认已经有public abstract了,所以写上会变成灰色
    public abstract void run();
    
    //也可以直接省略public abstract
    void run2();
}

接口只是起到定义方法的作用,要实现方法还需要一个实现类

定义一个实现类,命名规范,一般要在实现类的名后添加一个Impl:
通过implements关键字链接定义好的接口,并重写接口中定义的方法

public interface UserServer {
   

    void insert();
    void delete();
    void update();
    void query();
}
public class UserServerImpl implements UserServer{
   
    @Override
    public void insert() {
   

    }

    @Override
    public void delete() {
   

    }

    @Override
    public void update() {
   

    }

    @Override
    public void query() {
   

    }
}

一个类可以链接多个接口:接口之间用逗号分隔。

接口从侧面实现了extends无法实现的多继承。
如果在接口中定义常量:

public interface UserServer {
   

    //默认接口中定义的是常量public static final
    public static final int age=99;
    
    //也可以省略public static final 也是默认常量
    int ages=100;
    
    
    void insert();
    void delete();
    void update();
    void query();
}


一般不用


18. 内部类

1. 成员内部类

例:

public class Outer {
   

    private int age;
    public void out(){
   
        System.out.println("这是外部类方法");
    }

    public class Inner{
   
        public void in(){
   
            System.out.println("这是内部方法");
        }
    }
}
public class Application {
   

    public static void main(String[] args) {
   
        Outer outer = new Outer();
        outer.out();

        //通过这个外部类来实现内部类
        Outer.Inner inner = outer.new Inner();
        inner.in();

    }
}

可以通过内部类来获取到外部类的私有属性

2. 静态内部类

通过static修饰的内部类

3. 局部内部类

public class Outer {
   

    //局部内部类
    public void methon() {
   
        class A {
   
            public void in() {
   
    
            }
        }
    }

}

扩展:

public class Outer {
   


}

//一个java类中可以有多个class类,但是只能有一个public修饰的class类
class A{
   
    public static void main(String[] args) {
   
        
    }
}

4. 匿名内部类

public class Outer {
   

    public static void main(String[] args) {
   

        //没有名字的初始化类和接口,不需要将实例保存在变量中
        new A().eat();

        //会返回一个UserServer的对象
        UserServer userServer = new UserServer() {
   

            @Override
            public void run() {
   

            }
        };
    }
}

class A {
   
    public void eat() {
   
        System.out.println("吃");
    }
}

interface UserServer {
   
    void run();
}



转载:https://blog.csdn.net/zhouqiyuan1233/article/details/115176937
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场