一篇文章带你详细了解Java中的面向对象

目录

何为面向对象,对象的含义是指具体的某一个事物,比如在现实中可以看得见,摸得着的事物。而对象有着两个含义,一个是数据(特征),一个是动作(行为)。对象就是二者的结合体。
在这里插入图片描述
我们可以拿图中的猫为例,这只花猫就是一个具体的对象,它的数据就比如指的是它的体重,它的年龄。而动作就包含它的爬行,吃饭等等。
而面向对象编程的过程就是
找对象—>建立对象—>使用对象—>维护对象
我们经常那面向对象和面向过程编程来想成对比

面向过程面向对象
设计模式自顶向下自下而上
程序单元函数模块对象
设计方法程序=算法+数据结构程序=对象=数据+方法
优点相互独立,代码共享,性能相对较高接近人的思维方式,使用灵活,易维护,易复用,易扩展
缺点修改、维护困难性能相对较低
我们可以举一个例子来说明这两种过程,比如我们把大象装进冰箱如何操作?
  • **面向过程:**第一步,我们首先要把冰箱门打开,然后把大象放进冰箱,最后关上冰箱门。
  • **面向对象:**我们首先操作冰箱这个对象,通过冰箱对象的开门、关门方法,以及大象的走进去这个方法或者说行为,即可以完成这个问题。
    我们可以把具有同一特征或者行为的对象进行抽取,归纳或者总结,而这样就诞生了类的概念。比如有两只猫,同样都是猫,那么他们就都有吃鱼这个行为。我们就可以把猫视作类,而每一只猫就是具体的对象

类的定义

类的一般结构

[类修饰符] class 类名称
{
    [修饰符] 数据类型 成员变量名称;
        ......
    [修饰符] 返回值的数据类型  方法名(参数1,参数2,参数3)
    {
        语句序列;
        return [表达式]
        
        }    


}

在其中,方括号[ ]的修饰符是可选项,它是一组限定类、成员变量和成员方法是否可以被程序里的其他部分访问和调用的控制符。其中,类修饰符分为一下四种

修饰符含义
public将一个类声明为公共类,它可以被任何对象访问
abstract将一个类声明为抽象类,需要子类提供该类的方法实现,所以不能创建该类的实例
final将一个类声明为最终类即非继承类,表示它不能被其他类继承
缺省缺省修饰符时,则表示只有在相同包中的对象才能使用这样的类

成员变量

[修饰符] 变量类型 变量名[=初值]

一个类的成员变量描述了该类的内部信息,一个成员变量可以是基本类型变量,也可以是对象,数组等其他引用数据类型。成员变量的修饰符如下表所示

public公共访问控制符。指定该变量为公共的,它可以被任何对象的方法访问
private私有访问控制符。指定该变量只允许自己类的方法访问,其他任何类(包括子类)中的任何其他方法不能访问此变量
protected保护访问控制符。指定该变量只可以被它自己的类以及子类或者同一个包的其他类访问,在子类中可以覆盖此变量
缺省缺省访问控制符,表示在同一个包中的类可以访问成员变量,而其他包中的类不能访问
final最终修饰符。指定该变量的值不能改变
static静态修饰符,指定该变量被所有对象共享,即所有的实例都可以使用该变量
transient过渡修饰符,指定该变量是一个系统保留、暂无特别作用的临时变量
volatile易失修饰符。指定该变量可以同时被多个线程修改

成员方法

声明的语法如下
[修饰符] 返回值的具体类型 方法名(参数1,参数2等等){ 语句序列; return [表达式]}
说明:如果不需要传递参数到方法中,只需要将方法名后的圆括号写出即可。
方法的定义中修饰符是可选项,方法的修饰符比较多,下面我拿常用的给大家列举

修饰符含义
public公共访问控制符,指明该方法为公共的,它可以被任何对象的方法访问
private私有访问控制符,指定该方法只允许自己的类方法访问,其他任何类中的方法均不能访问此方法
protected保护访问控制符,指定该方法只能被它的类以及其子类或者同一包中的类访问
缺省缺省访问控制符,指明在同一个包的类可以访问此成员方法,而其他包中的类能访问该成员方法
final最终修饰符,指明该方法不能被覆盖
static不需要实例化就能调用
abstract抽象修饰符,指明该方法只声明方法头,没有方法体,抽象方法需要在子类中被实现

成员变量与局部变量的区别

  1. 从语法上来看,成员变量是属于类的,而局部变量是属于方法中定义的变量,或者方法所需要的参数
  2. 从内存的存储上来看,成员变量是对象的一部分,对象储存在堆之中;而局部变量在方法中,方法要进入栈。
  3. 从生存时间来看,成员变量是对象的一部分,它随着对象的消失而消失,而局部变量一旦方法执行完毕就会自动消失
  4. 成员变量如果没有被赋初值,她会以自动以类型来赋初值,但是局部变量不会自动赋值,它必须显式赋值才能使用

对象的创建和使用

对象是类的实例,所以对象是属于某个已知的类,因此要创建属于某个类的对象,可通过两个步骤
(1)声明指向”由类所创建的对象“的变量
(2)利用new运算符所创建的新对象,并指派给前面所创建的变量

Cylinder volu;
volu=new Cylinder();

通过这两个步骤我们也可以直接合成一句Cylinder volu=new Cylinder()
我们可以详细看看创建的过程
在这里插入图片描述

在栈中生成了一个变量,变量的值为地址值,指向堆空间所建立的对象。因此可以说volu就是new的一个引用型变量。当一个对象被创建时,如果并没有为其赋值,则系统会自动的对其进行赋值
按照下表的规则

成员变量类型初始值成员变量类型初始值
byte0double0.0D
short0char‘\u0000’
int0booleanfalse
long0Lfloat0.0F
所有引用变量null

要注意我们每new一个对象。堆空间就会开辟一个对象,所以当我们修改其中一个值时,其他对象的属性并不会被修改。
在类的内部中,方法与方法之间也可以被相互调用。若当我们向方法中传入参数时,且参数名称与类中的属性名称相同时,我们应该用this来标识成员变量

方法中的参数与返回值详解

一个方法如果没有返回值,则前面必须用void来修饰,如果返回的数据类型为简单数据类型,则需要标识即可,如果要返回一个一维数组,则加上int[]即可,若是二维,则要加上int[][]

方法中的可变参数

在方法调用并传递参数时,将接受不固定个数的参数称为可变参数,接受可变参数的语法格式如下

返回值类型 方法名 (固定参数列表,数据类型 …可变参数名){方法体}

注意:可变参数只能放在参数最后。

匿名对象

我们可以不定义对象的引用变量而直接调用这个对象的方法,这样的对象称为匿名对象

Cylinder volu=new Cylinder()
volu.setCylinder(2.5,3,3.14)

我们可以直接改写为new Cylinder().setCylinder(2.5,3,3.14)
一般来说使用匿名对象通常有两种情况

  1. 一个对象只需要进行一次方法调用,就可以使用匿名对象
  2. 将匿名对象作为一个实参传给一个方法调用

方法重载

方法的重载很简单,指的就是在同一个类中具有相同名称的多个方法,这多个同名方法如果参数个数不同,或者说参数个数相同但类型不同,则这些同名的方法就具有不同的功能。
但是也要注意 Java语言中不允许只有返回值不同的重载。我们可以看一个重载的例子

public class boy {
    String name;
    int age;
    char sex;

    public String getName() {
        return name;
    }
    public void getName(String s){
        System.out.println(s);
    }
    public void setName(String name) {
        this.name = name;
    }
}

如上述代码中的两个getname方法就构成了重载。

构造方法

构造方法是指对象被创建时候初始化对象成员变量的方法,构造方法的名字必须和它类名相同,构造方法的返回值类型就是它本身。构造方法在创建对象时候就会自动调用并且执行,

构造方法的重载

一般情况下,一个类有多个构造方法,这些方法都是类的名字,所以这些方法构成了重载,我们可以构建多个参数的构造方法。

package com.test.lei;

public class boy {
    String name;
    int age;
    char sex;
    boy(){

    }
    boy(String name){
        this.name=name;
    }
    public String getName() {
        return name;
    }
    public void getName(String s){
        System.out.println(s);
    }
    public void setName(String name) {
        this.name = name;
    }
}

代码中的两个boy构造方法就构成了重载。

从一个方法内调用另一个构造方法
package com.test.lei;

public class boy {
    String name;
    int age;
    char sex;
    boy(){

    }
    boy(String name){
        this.name=name;
    }
    boy(String name,int age){
        this(name);
        this.age=age;
    }
    public String getName() {
        return name;
    }
    public void getName(String s){
        System.out.println(s);
    }
    public void setName(String name) {
        this.name = name;
    }
}

静态变量、静态方法、静态初始化器

用static修饰符修饰的为类变量,它并不是储存在具体的一个对象空间中,而是保存在类的公共的存储单元之中,因此如果任何一个变量修改其的值,那么它就会被永久更改,当然也意味着静态变量不需要实例化对象就可以被调用,
与静态变量类似,静态方法也由static来修饰,使用静态方法也不需要去创建对象但是要注意,在静态方法之中不能使用this或者super。
静态初始化器则是在类被加载进入内存时调用,构造器是每new一次调用一次,而静态初始化器只调用一次。

有关引用变量,基本类型变量的应用

当我们通过赋值语句,将一个对象赋值给另一个对象时,由于对象是引用型变量,它们指向的地址值相同,因此如果一个值被修改,那么另一个对象变量的值也会被修改。当然对象可以作为返回值,我们只需要在前面声明返回值的类名。当我们在传递数组作为实参时只需要给出数组名即可。

面向对象具有三大基本特征

继承

在日常生活中,我们都了解过继承这个概念,
在这里插入图片描述

比如在这个图中。食草动物和食肉动物都继承于动物,而兔子和羊都继承于食草动物,狮子和豹子继承于食肉动物。虽然食草动物和食肉动物都隶属与动物,二者的属性和行为不同,说明子类会具有父类的一般特征,也会具有自身的特性。
Java中的继承并不支持多重继承,所以一个类只能有一个父类,但是一个父类也可以有多个子类。
Java中有一个java.long.Object的特殊类,所有类都是直接或者间接的继承该类得到的。

子类的创建
class SubClass extends SuperClass{}

但是我们在创建子类时候会发现,如果没有用super()来调用父类中特殊的构造方法,系统会自动调用父类的无参构造方法,因此,如果父类中只定义了有参数的构造方法,而在子类中的构造方法中又没有用super()来调用父亲中特定的构造方法,则编译时会发生错误。当然,super()必须放在构造方法的第一行。

方法的覆盖(重写)

我们可以在子类中重写父类已经构建的方法,我们要保持与父类中完全相同的方法头声明,要有完全相同的方法名,返回值类型,和参数列表

多态

多态也就是通过父亲的对象访问子类的成员。创建父亲类型的变量指向子类对象,即将子类对象的变量赋值给父亲类型的变量,这种技术成为‘向上转型’。向下转型是指将一个比较具体的类转化为一个较为抽象的类,

不可被继承的成员与最终类

如果一个类被final修饰符所修饰时,则说明这个类不能被继承,则该类也不能有子类。一个变量若被static和final所修饰,那么也就是说它就是常量,且只能在定义时被赋值,如果一个成员变量只用final来修饰而不用static修饰,则只能赋值一次,不能默认。这种智能在定义变量时赋值或者构造器赋值。

Object类

Object类是所有类的子类,它包含着四个常用的方法

equals()方法

该方法多用于来比较,如果是字符串类型的变量的值,equals用来比较两个字符串中所包含的内容是否相等,而对于非字符串类型的变量equals用来比较的是堆地址中的首地址和==相同。

toString()方法

多用来将该对象的内容转化成字符串,并返回其内容,但是返回的大多是一些没有意义且看不懂的字符串,因此当我们一般需要使用它时,通常要对其进行重写。

getClass()方法

该方法的功能是返回运行时对象所属的类Person per=new Person(”张三“) Class obj =per.getClass()
它可以返回其类型。

对象运算符instanceof

instanceof是Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false。

抽象类

在Java中有着专门做父类的类抽象类,它的作用类似于模版
结构体


abstract class 类名
声明成员变量
返回值的数据类型 方法名(参数表)
{
}

抽象类的方法有两种,一种是带有方法体的一般方法,一种是没有方法体的"抽象方法",该方法就声明返回值的数据类型、方法名称、和所需的参数,但并没有方法体。
抽象类的子类必须实现父类中的中的所有抽象类,或者也将自己声明为抽象的,由于抽象类是需要被继承的,所以抽象类不能由final来修饰。当然抽象类不一定包含抽象方法,但包含抽象的方法的类一定要声明为抽象类,抽象类可以定义构造方法,但是它只能用protected来修饰,原因是它只能被子类所访问。

接口

接口的结构与抽象类相似,本身也具有数据成员,抽象方法,默认方法和静态方法

  1. 接口的数据成员都是静态的且必须初始化,即数据成员必须是静态常量,
  2. 接口中除了声明抽象方法外,还可以定义静态方法和默认方法,但不能定义一般方法。
    接口与类相似点:
    (1)一个接口可以有多个方法。
    (2)接口文件保存在 .java 结尾的文件中,文件名使用接口名。
    (3)接口的字节码文件保存在 .class 结尾的文件中。
    (4)接口相应的字节码文件必须在与包名称相匹配的目录结构中。

接口的多继承

public interface Hockey extends Sports, Event

我们可以使用接口来间接的解决多重继承问题,并实现更强的功能。
虽然一个类只能有一个直接父类,但是它可以同时实现若干个接口。

在接口的多重继承之中,可能会出现子接口和父接口同名的常量或者相同名称的方法,但在父接口中的常量被隐藏,方法被覆盖,要解决这种冲突,可以在接口的实现类中提供同名方法的一个新实现,或者引用父接口的默认方法,super.默认方法名()

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值