22bm_java基础面向对象

Java面向对象OOP

1.面向过程和面向对象

1.1面向对象思想:

  • 分类的思维模式
  • 思考问题首先考虑解决问题需要哪些分类
  • 然后对这些分类进行单独思考
  • 最后才对某个分类下的细节进行面向过程的思索
  • 适合处理复杂的问题
  • 适合处理需要多人协作的问题

对于描述复杂的事务,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是具体到微观操作,仍然需要面向过程的思路去处理。

1.2OOP本质

以类的方式组织代码,以对象的组织(封装)数据。

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

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

对象是抽象的具体实例

2.构造器

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

  • 类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有以下两个特点:
  1. 必须和类的名字相同
  2. 必须没有返回类型,也不能写void
  • 一旦定义了有参构造,无参就必须显式定义,否则无参不会默认生成,无参构造器调用不到
  • alt+insert自动生成快捷键,列表中有constructor,可自动生成构造函数。

3.创建对象内存分析

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);
        
        Pet cat=new Pet();
    }
}
public class Pet {
    public String name;
    public int age;
    //无参构造
    public  void shout(){
        System.out.println("叫了一声");
    }
}

3.1程序开始执行

将主类加载进方法区,静态方法随类一起加载,字符串加载进常量池,age是一个int类型的数字。

方法区是堆内一个特殊区域

image-20221122094239099

3.2接下来执行main方法,

main在栈底,栈里所有东西结束时,main方法从栈里弹出,程序结束。栈中一些方法,和一些对象的引用。

image-20221122095218643

3.3mian方法走到第一步,new Pet()

Pet类被加载,里面name默认null,age默认0

image-20221122095501839

3.4生成一个具体对象 dog

栈里dog是一个引用变量名,真正对象在堆里

image-20221122095718355

3.5对象里面的属性赋值

把“旺财”丢给了name,所以name才有了值。字符串保存在常量池中。

image-20221122095825795

接下来给age赋值

image-20221122100009586

3.6接下来Pat cat=new Pet()

image-20221122100238601

3.7注意点

静态方法区。静态方法随类加载而加载,好处是,所有对象可以直接调用。

image-20221122100425990

对象的引用:除基本数据类型之外,都可以叫做引用数据类型。对象是通过引用来操作的:栈—>堆

默认初始化:

  • 数字:0 0.0
  • char:u0000
  • boolean: false
  • 引用:null

4.封装

  • 程序设计要追求“高内聚,低耦合”。

    • 高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;
    • 低耦合:仅暴露少量的方法给外部使用。
  • 封装(数据的隐藏)

    • 通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏
    • 属性私有,set/get
  • 好处

    • 提高程序的安全性,保护数据。set中可以自定义一些验证方法
    • 隐藏代码的实现细节
    • 统一接口。所有的方法都是get、set形成了一个规范
    • 提高了系统的可维护性。良好的封装利于修改内部代码

5.继承

  • 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
  • extends的意思是“扩展”。子类是父类的扩展。
  • Java中类只有单继承,没有多继承。
  • 继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
  • 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。
  • 子类和父类之间,从意义上讲应该具有“is a”的关系。
  • ctrl+H快捷键继承树。
  • Java中,所有类,都默认或间接继承Object类。
  • this当前类中,super父类中,普通方法调用的也是当前类中的。私有的东西无法被继承。
  • 子类构造器中,隐藏代码,super()。因此new 一个子类时,会默认先执行父类的无参构造方法。且调用父了的构造器时,super(),代码必须写在子类构造器方法的第一行。构造器调用构造器时,this、super都要放在构造器代码的第一行。
  • super必须智能出现在子类的方法或者构造方法中。
  • super和this不能同时调用构造方法。

5.1重写

  • 重写都是方法的重写,和属性无关。

  • 父类的引用指向了子类

    • B b=new A();
      b.test();
      
  • 方法的调用只和左边,定义的数据类型有关

    • A a=new A();
      a.test;
      
  • @Override重写

    • image-20221122105828828
  • 子类不能重写父类中声明为final或static或private的方法。

  • 静态方法是类的方法,非静态方法是对象的方法,

5.1规则

  • 方法名必须相同
  • 参数列表必须相同
  • 修饰符,范围可以扩大,但不能缩小
    • public>protected>default>private
  • 抛出的异常范围可以被缩小,不能扩大
    • ClassNotFoundException–>Exception(较大)
  • 子类的方法和父类必要一致,方法体不同。

5.2为什么需要重写

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

6.多态

  • 动态编译:类型的最终转态只有在执行过程中才确定,类型:可扩展性

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

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

    • Student extends Person
      //一个对象的实际类型是确定的
      //new Student();
      //new Person();
      /*可以指向的引用类型就不确定了,父类的引用指向子类*/
          Student s1=new Student();
      Person s2=new Student();
      Object s3=new Student();
          //子类重写了父类的方法,执行子类的方法
      //子类Student重写了父类的run方法
      s1.run();//执行子类的
      s2.run();//执行子类的
      //都有run,程序执行时再确定执行哪个
      //父类中没有eat方法
      s1.eat();//执行
      s2.eat();//报错,父类中无此方法((Student)s2).eat(),强制转换后可以
      //结论:对象能执行哪些方法主要看左边Person s2的类型,与右边关系不大 
      

6.1存在的条件

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

6.2注意事项

  • 多态是方法的多态,属性没有多态
  • 父类和子类,有联系,否则类型转换异常!(ClassCastException)
  • 存在条件:继承关系,方法需要重写,父类引用指向子类对象,以下不能重写
    • static方法,属于类,不属于实例
    • final 修饰的
    • private私有方法

6.3Instanceof

运行时,指出对象是否是特定类的一个实例。返回一个布尔值,这个对象是否,是这个特定类,或者是它的子类,的一个实例

  • result = object instanceof class
  • Result:布尔类型
  • Object:必选项。任意对象表达式
  • Class:必选项。任意已定义的对象类。
  • 如果 object 是 class 的一个实例,则 instanceof 运算符返回 true
x Instanceof y;//xy之间没有父子关系就会编译报错
//true或者false是看x所指向的实际类型是不是y的子类型,
//如果x指向的类型跟y是有关系的,编译也会通过
//Object>String
//Object>Person>Teacher
//Object>Person>Student
Object object=new Student();
sout(object instance of Student);//true
sout(object instance of Person);//true
sout(object instance of Object);//true
sout(object instance of Teacher);//false
sout(object instance of String);//false

Person erson=new Student();
sout(erson instance of Student);//true
sout(erson instance of Person);//true
sout(erson instance of Object);//true
sout(erson instance of Teacher);//false
sout(erson instance of String);//编译报错,两者没有半毛钱关系
sout(Student instance of Teacher);//编译报错,同级
Student tudent=new Student();
sout(tudent instance of Student);//true
sout(tudent instance of Person);//true
sout(tudent instance of Object);//true
sout(tudent instance of Teacher);//编译报错,同级
sout(tudent instance of String);//编译报错

7.static关键字

7.1存在意义

  • 主要意义,创建独立于具体对象的域变量或者方法。即使没有创建对象,也能使用属性和调用方法
  • 比较关键的作用就是 用来形成静态代码块以优化程序性能,在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次

7.2特点

  • static修饰的变量或者方法不属于任何一个实例对象,而是被类的实例对象所共享
  • 该类第一次加载的时候,就会加载被static修饰的部分,而且只在类第一次使用时加载并进行初始化,注意这是第一次用就要初始化,后面根据需要是可以再次赋值的
  • static变量值在类加载的时候分配空间,以后创建类对象的时候不会重新分配。
  • 被static修饰的变量或者方法是优先于对象存在的,也就是说当一个类加载完毕之后,即便没有创建对象,也可以去访问

7.3应用场景

如果某个成员变量是被所有对象所共享的,那么这个成员变量就应该定义为静态变量。

  1. 修饰成员变量

  2. 修饰成员方法

  3. 静态代码块

  4. 修饰类【只能修饰内部类也就是静态内部类】

  5. 静态导包

    1. import static
      

      这两个关键字连用可以指定导入某个类中的指定静态资源,并且不需要使用类名调用类中静态成员,可以直接使用类中静态成员变量和成员方法

7.4静态变量与实例变量

  • 静态变量:
    静态变量由于不属于任何实例对象,属于类的,所以在内存中只会有一份,在类的加载过程中,JVM只为静态变量分配一次内存空间。

  • 实例变量:
    每次创建对象,都会为每个对象分配成员变量内存空间,实例变量是属于实例对象的,在内存中,创建几次对象,就有几份成员变量。

  • 访问方法

    • 静态变量
      • 类名.静态变量
      • 对象.静态变量(不推荐)
    • 静态方法
      • 类名.静态方法
      • 对象.静态方法(不推荐)

7.4注意事项

  1. 静态只能访问静态。
  2. 非静态既可以访问非静态的,也可以访问静态的。

8.抽象类

  • abstract修饰符可以用来修饰方法也可以用来修饰类,抽象方法、抽象类。
  • 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类。
  • 抽象类,不能使用new关键字来创建对象,它是用来让子类继承的。
  • 抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。
  • 子类继承抽象类,就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。
  • 抽象类有构造器。

9.接口的定义与实现

9.1普通、抽象、接口

  • 普通类:只有具体实现
  • 抽象类:具体实现和规范(抽象方法)都有
  • 接口:只有规范,自己无法写方法,约束和实现分离,面向接口编程

9.2接口定义

  • 接口就是规范,定义的是一组规则,体现的是“如果你是,,则必须能,,”的思想。
  • 就扣的本质是契约,制定后大家都遵守
  • OOP的精髓,是对象的抽象,最能体现这一点的就是接口
  • 设计模式所研究的,实际上就是如何合理的去抽象,因此讨论设计模式都会针对具备了抽象能力的语言

培养自己的抽象思维。

9.3接口的作用

  1. 约束
  2. 定义一些方法,让不同的人实现
  3. public abstract
  4. public static final
  5. 接口不能被实例化,接口中没有构造方法,接口中不可以有构造方法(抽象类中可以有)
  6. implements可以实现多个接口
  7. 必须要重写接口中的方法

10.内部类

10.1成员(普通)内部类

  • public class Outer{
        public class Inner{}
    }
    
  • 依赖外部类对象而存在

  • 成员内部类中,不能定义静态成员

    10.1.1外部类调用内部类

    //怎样调用成员变量,就可以怎样调用成员内部类,
    //(是指,非静态可以直接调用静态,静态不可直接调用非静态这方面)
    public class Outer{
        //成员内部类
        public class Inner{public void in();}
        //外部类的非静态方法,访问成员内部类
        public void out(){
         Inner inner=new Inner();
        inner.in();
        }
     //外部类的静态方法,访问成员内部类
        public static void outSta(){
            Outer out=new Outer();
            Inner inner=out.new Inner();
            inner.in();
        }
    }
    
    

    10.1.2内部类调用外部类

    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);//10
            }
            //调用外部类的方法
            Outer.this.out();
        }
    }
    

10.2静态内部类

  • public class Outer{
        static class Inner{}
    }
    
  • 不需要依赖其外部类对象

  • 静态内部类中也无法访问外部类的非静态成员

  • 静态内部类可以用public,protected,private修饰

  • 外部类可以访问内部类对象所有访问权限的成员

  • 详解:外部类的非静态成员是属于每一个外部类对象的,而本身静态内部类就是独立外部类对象存在的,所以静态内部类不能访问外部类的非静态成员,而外部类依然可以访问静态内部类对象的所有访问权限的成员,和普通内部类相同。

    10.2.1外部类调用内部类

    //静态内部类
        public static class Inner{public void in();}
    //能怎样调用静态属性就能怎样调用静态内部类
    new Outer.Inner().in();//类. 调用方式 
    
    

    10.2.2内部类调用外部类

    public static class Inner{}
    //此时,System.out.println(id),获取不到id,解决方法,id修改为静态
    

10.3局部内部类

  • public class Outer{
        public void out(){
            public class Inner{}
        }
        
    }
    
  • 其声明在一个方法体 / 一段代码块的内部,

  • 在局部内部类前不加修饰符public和private,其范围为定义它的

    代码块

  • 不在定义类的定义域之内便无法使用,只能在out()方法中使用

  • 可以任意访问该方法out()内的局部变量

  • 其提供的功能使用匿名内部类都可以实现,而本身匿名内部类可以写得比它更简洁,

  • 因此局部内部类用的比较少

10.4匿名内部类

  • 是局部内部类的简要写法,可以在不声明类名的情况下,继承其他类并创建对象

  • 作用范围和局部内部类完全一致

  • 有多种形式,其中最常见的一种形式莫过于在方法参数中新建一个接口对象 / 类对象,并且实现这个接口声明 / 类中原有的方法了

  •  // 1自定义接口
    	interface Inner {
            void in(int i);
        }
    
        private void demo() {
            // 在这个过程中会新建一个匿名内部类对象,
            // 这个匿名内部类实现了Inner 接口并重写 in 方法
            Inner inner = new Inner() {
    	        // 可以在内部类中定义属性,但是只能在当前内部类中使用,
    	        // 无法在外部类中使用,因为外部类无法获取当前匿名内部类的类名,
    	        // 也就无法创建匿名内部类的对象
                public void in(int i){
                    System.out.println("demo")
                }
            }
    
  • //2新建一个类对象 
    // new Object() 过程会新建一个匿名内部类,继承于 Object 类,
            // 并重写了 toString() 方法
            clickListener.onClick(new Object() {
                @Override
                public String toString() {
                    return "hhh";
                }
            });
    

10.5总结

image-20221122195211280

  • 静态内部类,作用范围,就像静态变量一样

    • 成员内部类,作用范围,就像成员变量一样
    • 局部、匿名内部类,作用范围,就像局部变量一样
  • 访问范围可以由内而外,不可,由外而内

    • 局部内部类,可以访问,静态属性、静态内部类

    • 静态内部类,访问不了,局部内部类

10.6使用情况

当不想让这个类,被外部访问时,可以使用内部类。对内,想要访问某些内部数据时,就得用到内部类,比如一些类的私有属性。

  1. 只想让类内部使用,就可以定义一个静态内部类
  2. 只是某个方法需要用到,就可以使用匿名内部类

在实际开发中,用的最多的就是静态内部类、匿名内部类。

Java8可以将匿名内部类写成lambda表达式,能够极大简化代码。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值