JavaSE-07 Opp面向对象(完整版)

语言: CN / TW / HK

JavaSE-07 Opp 面向对象(完整版)

1.方法的调用补充:package com.fenfen.oop.Demo1

1.1非静态方法下方法调用(不同的类)

①在Student的类中建立study的方法
        package com.fenfen.oop.Demo1;
        //学生类的方法
        public class Student {
            //方法
            public void study(){
                System.out.println("学生在学习");
            }
        }

        ②在Demo2类中调用Student类中的student方法
        //在别的类中调用
        package com.fenfen.oop.Demo1;

        public class Demo2 {
            public static void main(String[] args) {
                //在方法非静态下:实例化这个类
                //对象类型 对象名 = 对象值
                Student student = new Student();
                student.say();
                }
            }

1.2非静态方法下的方法调用(同个类)

public class Demo2 {

          //static和类(class:Demo2)一起加载
            public static void a(){
                b();//会报错原因:可以理解为:存在的去调用不存在的了
            }
            //没有static:这个得等到类实例化(new 后)才存在
            public void b(){
                a();
            }
        }

1.3 值传递:

//值传递
        public class Demo4 {
            public static void main(String[] args) {
                int a = 1;
                change(a);
                System.out.println(a);//输出仍然是a = 1
            }

            //无返回值
            public static void change(int a){
                //原因:a只是一个形式参数,a=10后没有返回值给到a,于是回到了主方法,主方法中有int a = 1,因此输出就是1了
                a = 10;
            }

            /*
            更加高端的解释:
                ①change方法调用完毕就出栈了,main方法还在栈中
                ②对于基本数据类型来说,给形参传递的是实参值的副本
                    而对于引用数据类型来说,传递则是地址的副本,但由于地址的副本和原来的相似,因此传递过去后的形参也指向同一个内存空间
             */

1.4 引用传递:

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

            change(person);
            System.out.println(person.name);//fenfen
        }

        //写个方法
        public static void change(Person person){
            person.name = "fenfen";//原因:引用传递:指针修改,因为引用指向原对象在内存中的区域,所以可以修改原对象的值

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

2. 对象的创建与分析:com.fenfen.oop.Demo2

2.1 类和方法的创建:Student,Application

//学生类
        public class Student {
            //①属性:字段
            String name;//未赋任何值,默认初始化为null
            int age;//为赋任何值,初始化为0

            //②方法
            public void study(){
                System.out.println(this.name+"学生在学习");//this表示当前这个类
            }
        }
public class Application {

            public static void main(String[] args) {
                //实例化:student对象就是一个Student类的具体实例
                Student student = new Student();
                Student xiaoming = new Student();
                Student xiaohong = new Student();

                //给对象赋值:        
                xiaoming.name = "小明";
                xiaoming.age = 3;

                //打印赋值后的对象属性:未赋值出来是null和0
                Person person = new Person();
                System.out.println(person.name);
                }
            }

2.2 构造器详解

2.2.1 无参构造器

public class Person {            
            String name;
            //1、一个类即使什么都不写,也会存在构造方法(和类名相同,且无返回值),即构造器:无参构造器
            //构造器的作用:实例化初始值:使用new对象,本质是在调用构造器
            public Person(){
                this.name = "fenfen";
                        }
public class Application {

            public static void main(String[] args) {

                Person person = new Person();
                System.out.println(person.name);//fenfen
            }

2.2.2 有参构造器

public class Person {            
            String name;
            //2、有参构造器:一旦定义了有参构造,无参就必须显示定义(就是有了有参,无参不能删,空着就好)

            public Person(){
                }

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

            public static void main(String[] args) {

        //实例化了一个对象:走的无参构造器
        Person person = new Person();
        System.out.println(person.name);

        //走有参构造器
        Person person1 = new Person("fenfen");
        System.out.println(person1.name);
            }
        }   

        //注:快捷键alt+insert然后点击constructor,可以选择无参或有参快速生成构造器

2.3 创建对象内存分析:com.fenfen.oop.Demo3

栈的概念是弹压,就像子弹壳装弹,一粒一粒压进去,但是打出来的时候是从上面打出来的,最先压进去的最后弹出来,如果进去顺序是123,打出来顺序是321,这就是后进先出

队列的概念就是我们平时排队,按次序来,你排在第1个,那你就第一个轮到,就是先进先出,先到先来

2.3.1 对应代码

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 =1;
                dog.shout();

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

2.3.2 对应内存顺序图:

3. 三大特性

3.1 封装:com.fenfen.oop.Demo4

3.1.1 相关概念:

原因:
a.程序设计应”高内聚,低耦合“,即类的内部数据操作细节不允许外界干涉,以及仅暴露少量方法给外部使用
b.封装:应禁止直接访问一个对象中数据的实际显示,通过操作接口去访问,以便信息隐藏

3.1.2 封装

//封装:属性私有 get/set
        public class Student2 {
            //名字、姓名、学号:一般封装对于属性来说比较多,对于方法少一些
            //学习、睡觉
            private String name;
            private int id;
            private char sex;
            private int age;

            //提供一些可以操作的这个属性的方法:因为上面private了
            //提供一些public的get、set的方法

            //①get获得这个数据
            public String getName() {
                return this.name;
            }

            //②set  给这个数据设置值
            public void setName(String name){
                this.name = name;

            }
            //注:快捷键alt+insert然后点击setter and getter,可以快速生成

            //③甚至可以在set里面写if判断来进行安全性检查
            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) {       

            Student2 s1 = new Student2();

            //s1.name = "fenfen";私有的不可调用
            String name = s1.getName();//get
            s1.setName("fenfen");
            System.out.println(s1.getName());//s1.getName().sout

            s1.setAge(999);
            System.out.println(s1.getAge());
                }
            }

3.1.3 封装的意义:

封装的意义:
        1、提高程序的安全性,保护数据
        2、隐藏代码的实现细节
        3、统一接口
        4、提高系统的可维护性
        5、封装和重载一般一起用的比较多

3.2 继承:com.fenfen.oop.Demo5

3.2.1 子类继承父类的方法与属性

public class Person {
            public int money = 10_0000_0000;
            public void say(){
            System.out.println("说了一句话");
            }
        }
public class Student extends Person{
            public static void main(String[] args) {
                Student student = new Student();
                student.say();
                System.out.println(student.money);
            }//子类继承父类,就会拥有父类的方法

3.2.2 子类继承父类私有的属性

public class Person {
            private int money2 = 99999999;  

            //get和set方法针对private搞个封装
            public int getMoney2() {
                return money2;
            }
            public void setMoney2(int money2) {
                this.money2 = money2;
            }
        }
public class Student extends Person{

            public static void main(String[] args) {    

                 Student student = new Student();
                 //针对private的封装方法的调用
                student.setMoney2(99);
                System.out.println(student.getMoney2());
            }
        }
        //注:   //ctrl+h可以弹出继承树

3.2.3 super详解

  1. super在属性上的运用
  • 父类
public class Person {
            //protected
            protected String name = "fenfen父类";
        }
  • 子类
public class Student extends Person{
            private String name = "fenfen子类";

            public void test(String name){
                System.out.println(name);//main传递过来的参数
                System.out.println(this.name);
                System.out.println(super.name);//super去调用父类的
            }
        }
  • Application类
public class Application {
             public static void main(String[] args) {
                com.fenfen.oop.Demo5.Student student1 = new com.fenfen.oop.Demo5.Student();
                student1.test("fenfenmain类");
                     }
                }
  1. super在方法上的运用
  • 父类
public class Person {
            public void print(){//如果是私有的方法,子类就不能直接访问了
            System.out.println("Person");
            }
        }
  • 子类
public class Student extends Person{

            public void print(){
            System.out.println("Student");
            }

            public void test1(){
                print();//当前方法
                this.print();//当前方法
                super.print();//父类的方法
    }

        }
  • Application类
public class Application {

            public static void main(String[] args) {
                com.fenfen.oop.Demo5.Student student1 = new com.fenfen.oop.Demo5.Student();
                student1.test1();
            }
         }
  1. super在无参构造器上的运用
  • 父类
public class Person {
            public Person(){
            System.out.println("Person无参执行了");
        }

            protected String name = "fenfen父类";
        }
  • 子类
public class Student extends Person{
            public Student() {
                //隐藏代码:调用了父类的无参构造
                //即有一行:super();且调用父类的构造器必须在子类的第一行
            System.out.println("子类的无参执行了");
            }

            private String name = "fenfen子类";

        }
  • Application类:
public class Application {
             public static void main(String[] args) {
                com.fenfen.oop.Demo5.Student student1 = new com.fenfen.oop.Demo5.Student();
                     }
                }
        /*
        Person无参执行了
        子类的无参执行了
        */
  1. super在有参构造器上的运用
  • 父类
public class Person {

            //整一个有参构造器
            public Person(String name){
                System.out.println("Person无参执行了");
                }
            }
  • 子类
public class Student extends Person{

            public Student() {
                super(name:"name");//记得写参数,才会去调用有参的
                System.out.println("子类的无参执行了");
            }

                private String name = "fenfen子类";

                }
  • Application类:
public class Application {
             public static void main(String[] args) {
                com.fenfen.oop.Demo5.Student student1 = new com.fenfen.oop.Demo5.Student();
                     }
                }

3.2.4 方法的重写:com.fenfen.oop.Demo5

  1. 提前介绍多态:有static
  • 父类
public class B {
            public static void test(){

                System.out.println("B=>test");
            }
        }
  • 子类
public class A extends B {
            public static void test(){

                System.out.println("A=>test");
            }
        }
  • Application类
public class C {
            public static void main(String[] args) {
                //方法的调用只和左边的类型有关,定义的数据类型有关
                A a = new A();
                a.test();//走的是A类的方法

                //A继承B,父类的引用指向子类
                B b = new A();
                b.test();//走的B类的方法
            }

        }
  1. 方法重写:非静态
  • 父类
public class B {
            public void test(){

                System.out.println("B=>test");
                }

            }
  • 子类
public class A extends B{
            //重写1
            @Override//把static去掉,这个就是注解:有功能的注释
            public void test() {
                System.out.println("A=>test");
                }
            }
  • Application
public class C {
            public static void main(String[] args) {

                A a = new A();
                a.test();//A=>test

                B b = new A();
                b.test();//A=>test
            }
        }

总结看看:

/*第二次用重写的没有static的结果截然不同:
        有static静态时:b调用的是B类的方法,因为b是用B类去定义的
        没有static静态时:b调用的是对象的方法,b是用A类new的

        重写:需要有继承关系,而且是子类重写父类
        1、方法名必须相同
        2、参数列表必须相同
        3、修饰符:范围可以扩大:
            private--->default---->protected---->public
        4、重写可能会抛出异常:范围可以被缩小,但不能被扩大
            ClassNotFoundException

        注意:子类的方法和父类必要一致:方法体不同

        为啥要重写:override
        1、父类的功能子类不一定需要,或者不一定满足

3.3 多态:com.fenfen.oop.Demo6

3.3.1 多态的创建

public class Main {
            public static void main(String[] args) {
                //一个对象的实际类型是确定的
                //new Student();
                //new Person();

                //可以指向的引用类型就不确定了
                Student s1 = new Student();//Student能调用的方法都是自己或者是继承来的:Student类继承了Person类
                //①父类的引用指向子类的类型
                Person s2 = new Student();//父类的可以指向子类,但是不能调用子类特定的方法
                //②指向Object
                Object s3 = new Student();
                    }
            }

3.3.2 多态方法的调用

  • 父类
public class Person {
            public void run(){
                System.out.println("run");
                }

                }
  • 子类
public class Student extends Person{
        //重写下父类的方法

            @Override
            public void run() {
                System.out.println("son");
            }

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

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

            Student s1 = new Student();

            Person s2 = new Student();

            s2.run();//子类重写了父类的方法,因此父类的方法调用的时候变成子类了
            s1.run();
            s1.eat();
            ((Student)s2).eat();//强制转换(高类型转成) ,Person里面没有eat方法,所以强制转换成Student去调用
                }
            }

总结一下 :

/*
        多态注意事项:
        1、多态是方法的多态,属性没有多态
        2、父类和子类,有联系   如不符合:会出现异常ClassCastException!
        3、存在条件:①继承关系②方法需要重写③父类引用指向子类对象 Father f1 = new Student();
           有些方法不能重写:
           ①static静态,修饰的方法,属于类,不属于实例
           ②final常量,修饰的
           ③private方法:
        */

3.3.3 instance of和类型转换

  1. instance of
public static void main(String[] args) {
        //Object > String
        //Object > Person > Student
        //Object > Person > Teacher

        Object student2 = new Student();
        //instanceof判断左边对象是否是右边类的一个实例
        System.out.println(student2 instanceof Student);//看看是不是Student类型呢true
        System.out.println(student2 instanceof Person);//看看是不是Student类型呢true
        System.out.println(student2 instanceof Object);//看看是不是Student类型呢true
        System.out.println(student2 instanceof Teacher);//看看是不是Student类型呢false     
                                                        //因为没有new:object和Teacher
        System.out.println(student2 instanceof String);//看看是不是Student类型呢false

                }
        }
       /*总结一波:
        System.out.println(X instanceof Y);能不能编译通过取决于X、Y有没有父子关系
         */
  1. 类型转换
  • 父类
public class Person {
            public void run(){
                System.out.println("run");
                }

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

                //父类                子类
                //高                  低
                Person student = new Student();
                //student.go();报错原因:student属于Person,Person中没有go
                //student将这个对象转换未Student类型,我们就可以使用Student类型的方法了:高往低走

                Student student1 = (Student) student;//(Student)student;
                student1.go();
                ((Student)student).go();//前面写成一句话完成类型转换

                //低                 高
                //子类转换为父类,可能回丢失原来自己的方法
                Student student2 = new Student();
                student2.go();
                //把student变成person类型
                Person person = student2;
                //person.go();就用不了了

                }
            }

3.3.4 static关键字详解:com.fenfen.oop.Demo7

  1. static在属性上的使用
public class Student {
            //静态属性
            private static int age;//静态的变量
            private double score;//非静态变量
public static void main(String[] args) {
                student student = new Student();

                //用对象输出
                System.out.println(student.score);//student.score.sout
                //用类输出
                System.out.println(Student.age);
                //System.out.println(Student.score);没有static这个就不行
                //或者直接输出
                System.out.println(age+"kkkkk");
                     }
                }
  1. static在方法上的使用
public class Student {
            //静态方法
            public void run(){
            }

            public static void go(){
            }
public static void main(String[] args) {
                Student student = new Student();
                //方法调用
                //用对象调
                student.run();
                student.go();
                //用类调
                Student.go();
                //Student.run();没有static这个就不行:具体原因,现在是静态方法,只能去调静态方法的
                //直接调
                go();
                }
            }
  1. static在代码块、构造器上的运用
public class Person {

            //代码块
            {
                System.out.println("匿名代码块儿,一般会根据对象每次都跑,所以会被用来赋予初始值");
            }
            //静态代码块
            static {
                System.out.println("静态代码块儿,这个反而执行的时候是最先的,而且我就跑一次,后面不玩了");
            }
            //构造器

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

            public static void main(String[] args) {

                Person person1 = new Person();
                System.out.println("===============");
                Person person2 = new Person();
            }
        }
  1. static在静态导入包的使用
package com.fenfen.oop.Demo7;

        //静态导入包的方法和常量
        import static java.lang.Math.random;
        import static java.lang.Math.PI;

        public class Test {
            public static void main(String[] args) {
                //System.out.println(Math.random());  不想怎么写可以在前面直接导包,但是记得写static
                System.out.println(random());
            }

4. 抽象类和接口:com.fenfen.oop.Demo8

4.1 抽象类

4.1.1 抽象对象和方法的建立

public abstract class Action {

            //约束
            //abstrct ,抽象方法,只有方法名字,没有具体的方法内容实现,并且抽象方法跟抽象类
            public abstract void doSomething();

            /*
            1、不能在这个抽象类new(在main中都不给new,只能靠子类去实现它(重写?
            2、抽象类中可以写普通的方法
            3、抽象方法必须在抽象类中
            抽象的抽象:约束

            抽象存在的意义:
                    例如游戏中,抽象出一定的内容,每创建一个角色就去继承这个抽象类,直接重写部分方法,改掉一些不必要的东西即可

             */

4.1.2 无法在其他类中new一个抽象类的对象

public class Main {
            public static void main(String[] args) {
               // new Action(); 不给new
            }
        }

4.1.3重写抽象的方法

public class A extends Action{
            //继承用了abstract的类会报错,必须得重写一下才可以
            //抽象类得所有方法,继承了他的子类,都必须要实现他的方法
            @Override
            public void doSomething() {
            }
        }

4.2 接口:com.fenfen.oop.Demo9

4.2.1 创建接口以及基本方法

//接口:用interface
        // 写简单方法,然后有一个对应实现类UserServiceimp
        public interface UserService {

            //public void run(){   此处需要加上abstract不然不给写方法
            //}

            //接口中的所有定义其实都是抽象的 public abstract的方法
            public abstract void run();
            void add(String name);
            void delete(String name);
            void update(String name);
            void query(String name);
            //接口中定义属性:就是一个常量,很少在接口中定义常量:默认public static final
            public static final int AGE = 99;
        }       

        public interface TimeService {
        void timer();

        }

4.2.2 接口对应的实现类

//一个类实现接口 implemnts 接口:可以继承多个接口
        //实现了接口中的类,就需要重写接口中的方法
        public class UserServiceimp implements UserService,TimeService{//可以实现多个接口,实现多继承

            //右击generate:implement methods或者ctrl+i快捷键

            @Override
            public void run() {

            }

            @Override
            public void add(String name) {

            }

            @Override
            public void delete(String name) {

            }

            @Override
            public void update(String name) {

            }

            @Override
            public void query(String name) {

            }

            @Override
            public void timer() {

            }

5 内部类:com.fenfen.oop.Demo10

5.1 类中类

5.1.1创建内中类

public class Outer {

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

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

                //获得外部类的私有属性:外部出现的id = 10
                public void getID(){
                System.out.println(id);
            }

            //可以在内部类Inner前加上static:
                // 但是会出现:静态的内部类无法访问非静态的内部属性
            }
        }

5.1.2 实例化并调用类中类

public class Main {
            public static void main(String[] args) {
                //new
                Outer outer = new Outer();

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

5.2 局部内部类(方法中的类)

public class Outer3 {
            //方法中的类:叫做局部内部类
            public void method(){

                class Inner{
                    public void in(){
                    }
                }
            }
        }

5.3 匿名内部类

public class Outer4 {

            public static void main(String[] args) {

                //一般是Apple apple = new Apple();
                //也可以是:没有名字初始类,不用将实例保存到变量中
                new Apple().eat();

                //接口重写下方法
                new UserService()
                //实际写全是:UserService userService = new UserService()
                {

                    @Override
                    public void hello() {

                    }
                };
            }
        }

        class Apple{
            public void eat(){
                System.out.println("1");
            }
        }
        //整一个接口
        interface UserService{
            void hello();

        }