ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java面向对象编程特点与用法

2021-03-16 23:32:07  阅读:103  来源: 互联网

标签:调用 Java 构造方法 子类 用法 面向对象编程 父类 方法 属性


1.什么是面向对象(Object-Oriented Programming,OOP)

  面向过程:按步骤去实现功能,适用于一些简单的问题。

  面向对象:首先思考问题如何分类,然后对问题的子类再细分,最后对分类下的细节进行面向过程的思考。适合处理复杂以及需要多方协作的问题。

  对于复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统;然后对于微观操作,我们则需要采用面向过程的思路去处理解决。

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

  抽象:对问题进行分析抽离出需要研究解决的特质。

  三大特性的简单理解(后续会有更具体的学习):

  1)封装:将代码要用的数据封装起来,一同使用;

  2)继承:子类父类的继承关系,子类会顺承父类的一系列特性;

  3)多态:对于一个方法,不同对象可能会有不同的形态。

  一般认识的角度来说,先有对象而后有类,对象是具体的事物,类是对对象的抽象。而从代码运行的角度来说,先有类才有对象,类是对象的模板(对象是以类为模板new出来的)。

 

  方法的调用:

  1)静态方法(static):直接调用。

  2)非静态方法:需要先将类实例化,再调用(new Student().method() 或者Student a = new Student(); a.method()

  要注意的是,static方法是随类产生同时生成的,而非静态方法需要先声明才可调用。所以在方法之间的调用时,要注意先后顺序,若在静态方法内调用非静态方法,可能会因为非静态方法还未实例化导致调用失败。

   

 

2.类和对象的创建

  类是一种抽象的数据结构,是对某一类事物整体描述/定义,但是并不能代表一个具体的事物,只属于这类事物的共有模板,比如,人都可以通过年龄、身高和体重等数据来描述。

  对象是类的具体实例,比如张三,以上面的类为模板,年龄是18,身高是170cm,体重是55kg等,能体现出这个人的具体属性或特点。

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

     结果:

   this.name:this指当前类,this.name即为当前类下的name属性。

 

5.构造器详解

   项目中新建一个类,直接查看项目的class文件,可以看到项目中默认生成了一个无形参无返回值的方法,名字与类名相同,这个方法即为一个构造器,也称构造方法。

   

 

   构造方法:当对某一个类创建对象时,必须调用对应的构造方法用来实例化对象(赋初始值),这个构造方法即为构造器,它必须和类的名字相同,并且没有返回类型,无void关键字。

    结果:

  除了程序自动生成的默认无参构造器,我们也可手动写一些无参或有参的构造器,比如调整属性的初始值等。下面是两个例子:

  无参构造:

    结果:

  有参构造:

    结果:

  (要注意的是,当已经定义了有参构造后,如果在main方法中还需使用无参构造,则必须自己显式定义一个无参构造,否则会报错)

  构造器:

  1)和类名相同;

  2)没有返回值。

  作用:

  1)使用new实例化一个对象时,实际上是在调用构造方法(构造器);

  2)构造器主要是用于初始化对象的值。

  ——alt+ins 可默认生成一个有参构造器(select none选项为无参)

 

6.创建对象内存分析 

  初始化类时,在堆中的方法区加载Test类及相关主方法和常量,栈中压入main方法。同时加载静态方法区的所有方法(static):

        

 

   实例化第一个Student类xiaoming,在方法区加载Student类对应的属性和方法,将引用变量名压入栈中,在堆中申请对应的内存空间0x0001,属性均为初始化默认值:

          

 

   提取Test类中的常量为实例的属性赋值:

               

 

   同理实例化第二个Student类,将引用变量名压入栈中,在堆中申请对应的内存空间0x0002,并为属性赋值:

       

 

 6.类和对象小结

   1)类和对象:

    类是一个抽象模板,对象是一个具体的实例;

  2)类的构成:

    a.静态的属性:属性

    b.动态的功能:方法

  3)对应的引用:

    基础数据类型(8种)和引用类型(除8种基本数据类型均为引用类型),对象是通过引用类型来进行操作的,即前面内存分析中从栈到堆的引用关系。

  4)属性:类中的字段(field),也称成员变量

    a. 默认初始化:

      数字:0或者0.0

      char类型:/u0000

      boolean类型:false

      引用类型:null

    b. 命名语法:修饰符 属性类型 属性名 = 属性值

  5)对象的创建和使用:

     ——必须使用new关键字创建对象,创建对象后会生成默认的构造方法(构造器),对象中还包含对应的属性和方法

 

 7.封装

   程序设计追求“高内聚,低耦合”,“高内聚”指类内部的数据操作细节自己完成,不允许外部干涉;“低耦合”指仅提供少量的方法供外部使用。数据封装就是相似的概念,一般的类会禁止直接访问内部数据的实际表示,而是提供对应的接口供外部访问,这也被称为信息隐藏。

  封装一般是对应类中的属性,通过private关键字将属性变成私有的,此时其他类不能通过“类.属性名”调用(报错如下),需要用到类提供的方法去调用或设置,比如getAge()、setAge()等。

    

    结果:

  对于类中的private属性,我们可以通过alt+ins的快捷键去快速设置对应的get/set方法。

  封装的意义:

  1)提高程序的安全性,保护数据;

  2)隐藏代码的具体实现细节;

  3)统一接口;

  4)提高系统的可维护性。

 

8.继承

  继承是类和类之间的关系,本质上是对一批类的抽象。除了继承之外,类与类之间的关系还有依赖、组合、聚合等。

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

  一般继承的是公有属性和方法(一般只有属性会被设置为私有),若需要用到父类的私有属性,也可以通过封装中的get/set方法去调取:如

    

  结果:

  修饰符的优先级顺序

  1)public

  2)protected

  3)default(一般未标明修饰符即为default属性)

  4)private(不可被继承)

  另外有final修饰符的类也不可被继承。

  通过ctrl+h可以查看当前类的继承树:

                 

  可以看到,所有类中都继承了一个Object父类,包括新增的全空的NewPerson类,我们实例化这个NewPerson类,然后可以发现其中仍然有很多方法可以使用。

  

   由此我们可以得知,在Java中,所有的类都默认直接或者间接继承Object类。

  另外要注意的是,Java中只有单继承,没有多继承。即一个子类只能有一个父类,但一个父类可能有多个子类。

  

9.Super详解

  相对于this修饰符,super有如下特点,主要用于指代父类的非private属性或一些方法:

  1)代表的对象不同

    this代表当前类对象的引用;

    super代表父类对象的引用;

  2)使用条件不同

    this没有继承也可以使用;

    super必须在继承了父类的子类中使用;

  3)代表的构造方法不同

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

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

  属性的实例:

    

 

 

  结果:

  

  方法的实例:

    

  结果:

  

  构造的实例:

    

 

  结果:

 

   

 

 

  在子类构造方法上直接加入父类的构造方法super();,可以看到结果一致。

   结果:

 

 

 

  注意点:

  1)super()调用父类的构造方法,必须位于构造方法中的第一位(最高优先级构造);

  

  2)super只能出现于子类的方法或构造方法中;

  3)super和this不能同时调用构造方法;

   结果:

  如果同时存在super()和this(),则会报错(因为二者都要求存在于构造方法中的第一行):

  

  4)私有的属性无法被继承;

  

 

 

   5)子类会默认调用父类无参构造,所有要求父类必须有无参构造方法。所以我们在给类编写有参构造方法时要注意补充无参构造,养成良好编程习惯。

    

  报错:

   

 

 

   备注:多级继承时,super指向的是当前类的上一级父类,若在上一级父类中未找到对应的属性或方法则继续向上搜寻。

 

10.方法重写

   重写是方法的重写,与属性无关,主要用于体现JAVA的多态性,当我们现在已有的方法已经被系统中的多处引用到了,突然我们的需求发生了很大的改变时(子类不一定需要父类的所有功能,或满足父类的所有条件),我们只需要子类重写这个方法,然后用子类去实现就行了,不用对系统去进行过多的改变。

  1)静态方法和非静态方法在方法重写中要注意区别:

  父类和子类的方法都为static静态方法,方法在类加载时就已经确定,调用结果只和引用的数据类型有关,方法只取决于等式左边引用的数据类型。

    

  结果:

  

 

 

  父类和子类的方法均非静态方法时,在声明实例时才加载方法,若父类的引用指向子类此时子类会重写父类的方法,父类的原方法会通过子类的重写方法进行操作

    

 

 

  结果:

  

  2)通过alt+ins快捷键快速重写方法:

   

  初始会默认调用父类方法:

   (平常可以通过左边这个图标确认当前方法是否属于重写方法)

  我们再根据需要去重写:

  

 

 

   

  方法重写的条件:

  1)需要存在继承关系,子类重写父类的方法;

  2)方法名和参数列表必须相同

  3)必须为非静态方法;

  4)方法的修饰词范围可以扩大,不能缩小。原本为default,可以重写成public或protected,但不能重写成private(public>protected>default>private);

  5)抛出的异常范围可以被缩写,但不能扩大(这里写了解,后面会详细学习)。

  简单来说,子类和父类的方法必须一致,但方法体不同。

  

11.多态

 

 

 

   同一方法可以根据发送对象的不同而采用多种不同的行为方式,这叫做多态。这体现了一种动态编译的思想,以提高程序的可拓展性。在多态中,一个对象的实际类型(new Student())是确定的,但是可以指向对象的引用的类型有很多。

  

  针对于引用类型及类方法的不同,有几点需要注意:

  1)多态是方法的多态,属性没有多态;

  2)类对象可以指向另一个类类型,但二者必须有所联系,如子类和父类有继承关系,父类对象才可指向子类,若没有联系会报异常:ClassCastException!;

  

  3)若两个类型之间存在同名方法,则子类可以通过重写方法来让父类对象调用;

    ——不能重写的方法:

      1)static方法,属于类,不属于实例;

      2)final类型属于常量类型,不能重写;

      3)private类型方法是私有的,不能重写。

  4)父类引用如果需要调用子类方法,可以尝试将父类对象强制转换成子类后再调用:((student) B). method()

  细节如下图所示:

    

  Main方法:

  

 

 

 

12.instanceof和类型转换

   instanceof一般用于判断一个对象是属于什么类型,返回Boolean值。

  现有继承关系如下:

  

 

 

   下面我们分别将不同等级的父类引用对象指向Student()子类,然后用instanceof判断这些对象的类型:

  

   注释掉编译报错语句后执行,结果为:

  

 

 

  结论:

  1)对象指向的实际类型(new Student())和要对比的类型若存在继承关系,则比较结果为真,否则为假;

  2)比较的对象引用类型(如Object obj)和要对比的类型必须存在继承关系,才可以使用instanceof比较,否则会报编译错误。

  类型转换

   

  

  注释掉编译报错语句,执行结果如下:

  

  1)子类转换为父类不用强制转换(向上转型),这里会损失子类的方法;

  2)父类转换为子类要强制转换(向下转型),会继承父类方法,但若子类重写了父类方法,这一类方法会被丢失。

  类型转换的作用:方便方法的调用,减少重复的代码,保证程序简洁。

 

 

 

13.static关键字详解

  static静态关键字可以用于类中的变量和方法。标有static关键字的变量和方法会在类加载的时候同时加载,便于程序的调用。

  1)静态变量

    静态变量通过类名访问,非静态变量通过声明类实例后调用。

   

  注释掉编译错误语句后,重新执行,结果:

  

 

 

  2)静态方法

    和静态变量一致,随类同时加载,可以直接通过类名调用。

   

  注释掉编译错误语句后,重新执行,结果:

  

  3)静态代码块、匿名代码和构造方法的优先级:

   

  结果:

  

 

 

  由结果可知:

    1)静态代码块随类加载同时执行,每次类加载只执行一次,与实例化对象无关;

    2)匿名代码块在每次实例化对象时都会第一个执行,一般用于配置默认值等操作;

    3)构造方法在匿名方法块执行之后执行。

  

  4)静态导入包

  当我们需要常用一些java工具类时,可以直接通过静态导入包来简化代码量。

  例如Math.random();这个生成随机数的方法,可以改为下面的方式:

   结果:

 

 

 

14.抽象类   

  通过abstract关键字来编写抽象类,主要是为了起到约束的思想,抽象类的抽象方法没有具体的方法体,只能通过子类继承后重写调用,这样可以以更灵活的方式编写方法,减少重复代码量,提高开发效率。

   

  

 

  结果:

 

  

 

 

  由此我们可以总结出抽象类的几个特点:

  1)抽象类本身不能通过new关键字声明实例,只能通过子类实现(约束思想);

  2)抽象类的abstract方法,继承了它的子类要么仍是抽象类,要么就必须重写对应的abstract方法去实现;

  3)抽象方法必须在抽象类中,通过子类重写去调用;

  4)抽象类可以有普通方法,通过继承的子类实例对象调用;

  5)抽象类的静态方法可以通过类名直接调用;

  6)抽象类中也存在默认构造方法,在非抽象子类声明实例时调用。

 

15.接口的定义与实现

  和抽象类类似,接口主要针对的也是面向对象中约束的编程思想,接口相对而言实现的是更专业的约束。在企业中,很多工作都是面向接口编程,接口将约束和实现方法分离,以抽象的思想提供一个基本的方法框架,其他人再在各自的实现类中根据需求重写接口的方法。

  接口声明关键字为interface,接口需要通过实现类来实现,实现类通过implements关键字实现对应接口,一个实现类可实现多个接口,以此来达到多继承的功能。实现类需要将接口中的所有方法重写,然后才能供对象调用。

  接口中所有定义的方法都是抽象的 public abstract。如果在接口中定义属性,那么这些属性都是常量,默认带public static final属性,但一般接口中不会定义属性(不建议)

  一般也可根据图标确认当前代码是类、抽象类或者是接口:

  类:  抽象类:  接口:

 

 

  另外,接口中也不含构造方法:

  

  代码实例:

  接口:

    

  实现类:

  

  主方法:

  

  结果:

  

 

16.N种内部类(拓展)

  下面一些比较特殊的代码,主要用于拓展,不推荐这些写法。

  成员内部类:

  实现方法:通过外部类来实例化内部类。内部类可以直接获得外部类的私有属性和私有方法。

   

 

   结果:

 

 

  静态内部类:无法直接获取外部类的私有属性和方法

  

 

  匿名内部类

  类:

   

  结果:

  接口:可以直接new对应的接口,但需要重写接口中的所有方法,这里声明的接口也是没有名字的,也为匿名内部类、

  

     

 

 

  局部内部类

  

 

  一个java类中可以存在多个class类,但只能有一个public类

   

标签:调用,Java,构造方法,子类,用法,面向对象编程,父类,方法,属性
来源: https://www.cnblogs.com/Kknock/p/14527251.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有