Java类和对象

Java类和对象

面向对象基本概念

对象

  我们可以把一切事物称为对象object),例如一台电脑,一个人,一栋房子等等,同样的敲代码,吃东西,睡觉也可以认为是对象。

  因此,一个对象一般有两方面特征:

  •   状态(又称为属性):用来描述对象的静态特征(例如人的身高、体重、肤色等等)。
  •   行为(又称为方法):用来描述对象的动态特征(例如吃东西、喝水、睡觉、行走等等)。

  在Java程序中,一切皆为对象。

  可以定义为具有类似状态和行为的对象的集合。如人类共同具有区别于其他动物的明显特征有直立行走,使用工具,思考等等,手机都具有打电话、发短信等功能。

  所有的事物都可以归到某一类中,例如人都可以归到人类中,电脑手机可以归到电子设备类中等等。

  属于类的某一个具体的对象称为该类的一个实例,例如智能手机是手机类的一个实例。

  基于以上分析,我们认为实例和对象是同一概念,后文将不区分两者。

  类与对象的关系就是抽象与具体的关系,可以简单比喻为类是一张蓝图(图纸上的房子是抽象的),而对象是依据这个类搭建起来的房子(房子是具体的)。

  在Java语言中,类是一种数据结构,要想得到对象,必须先定义类,然后才能创建对象。

消息

  对象与对象之间并不是孤立的,对象之间存在一定的联系,这种联系通过消息传递。例如程序员敲代码就是程序员这个对象向电脑这个对象传递消息。

面向对象的特性

封装性

  封装性:封装就是把对象的属性和方法结合成一个独立的系统单位,并尽可能的隐藏对象的内部细节。

  • 例如一个ATM机就是一个封装体,它封装了ATM的属性和方法。
  • 对于一个用户来说,接口部分是可见的,例如存取现金的功能,而实现部分是不可见的,例如用户输入金额后,只用在钱币的接口取钱即可,而ATM机是如何从保险箱取钱,并通过传送带送到出口,验钞,钱币不够了如何处理,发现假钞如何处理等等这些内部实现的细节并不可见。

  因此,封装提供对对象的保护,防止用户直接接触对象内部的细节。

继承性

  继承是生活中常见的一个方法,某人继承了父母的身高,外貌等等。继承可以分为单继承和多继承。

  • 单继承指的是子类只能从一个父类继承(即一个子类只有一个父类)
  • 多继承指的是子类可以从多个父类继承(即一个子类可以有超过一个父类)

  Java中,只有单继承,即一个子类只能从一个父类继承

多态性

  多态性是面向对象编程语言的一个重要的特性,多态可简单理解为同一个名字多种形态。

  面向对象中,多态有多种情况:

  • 静态多态:在同一个类中定义了多个名称相同的方法,即方法重载(overload)。
  • 动态多态:子类定义的与父类同名的方法,即方法重写(覆盖/覆写)(override)。

  除此之外,面向对象还有一些其他特性,而上述的三个特性是面向对象的最重要的三大特性。

  本文将着重介绍类的定义和对象的创建以及初始化相关知识,关于上述的三大重要特性,将在后边的文章中着重介绍。

类的定义

  类声明的一般格式:

[public][abstract|final] class ClassName[extends SuperClass][implements InterfaceName]{
	variable declarations;//成员变量
	method declarations;//成员方法
}

  一个完整的类定义如上所示,包括类的声明和类体(成员变量和成员方法)的定义。

  一个普通的类通常按如下方法定义:(以猫类为例)

public Class Cat{
	//成员变量
	String name;//猫咪的名字
	String sex;//猫咪的性别
	//其他可以描述猫咪属性的变量
	
	//成员方法
	//猫咪吃的行为
	public void eat(){
		System.out.println(name + "正在吃东西。");
	}
	//猫的其他一些行为
}

类声明

  在类的声明中,[]中的代码不是必须写的,而是依据实际需要进行添加。

类的访问限定修饰符

  限定访问是封装特性的一大体现,它表明了当前类的访问权限,在下文中,我们在着重介绍成员属性限定访问修饰符,它界定了比类更进一步的限定访问。

  类的访问限定修饰符为public或缺省:

  • public修饰的类表示公共类,即该类可以被任意包中的类使用。
  • 若缺省,表示该类只能被同一个包中的类使用。
类的其他修饰符
  • final:由单词的意思以可看出,表示最终,即由该修饰符修饰的类为最终类,其不能被继承。
  • abstract:抽象的,表示该类为抽象类,抽象类不能实例化,即不能由该类创建对象,但抽象类可以被继承,将在介绍多态性时具体介绍抽象类。

class ClassName

  类名由实现者来定义,通常是名词,类名除了遵守Java标准中规定的命名规范外,在Java程序猿中,约定俗称类名一律采用大驼峰命名方式(但不是强制的),而方法名和变量名则采用小驼峰命名的方式。

  可以不采用上述约定俗称的命名方式,但是这样会大大降低代码的可读性。

extends SuperClass

  extends表示延伸、扩大之意,即ClassName延伸于SuperClass,即ClassName继承了SuperName。(父类又叫基类、超类,子类又叫派生类)。

  例如猫类继承于动物类:

public class Animal{
	//类体,略
}
public class Cat extends Animal{
	//类体,略
}

  关于继承类的具体细节将在讲继承特性中具体详细的介绍。定义类时如果未指明所继承的父类,那么该类自动继承Object类,即上述代码中,Animal继承了Object类,其完整的写法应为public class Animal extends Object,,换句话说,继承Object的类可以省略extends部分,Object类是Java的根类,因为Java只支持单继承,所以一个类至多只能有一个超类。

implements InterfaceNameList

  implements为接口的关键词,定义了类实现哪个或哪些接口,一个类可以实现多个接口,多个接口之间用逗号隔开。一个类实现多个接口,其目的是为了弥补一个类只能继承一个父类的缺陷。接口的具体细节也在后边介绍。

  例如:猫类继承动物类实现吃和跑的接口

//动物类
public class Animal{
	//类体
}
//吃的接口
public interface IEatting{
	void eat;
}
//跑的接口
public interface IRunning{
	void run;
}
//猫类
public class Cat extends Animal implements IEatting,IRunning{
	//类体
}

成员的定义

  类的声明结束后是一对{}{}括起来的部分即为类体。类体中通常定义两部分类容:

  • 成员变量(属性)(variable declarations):提供了类即对象的状态。
  • 成员方法(method declarations):实现类和对象的行为。

成员变量的定义

  成员变量的声明格式:

[public|protected|private][static][final][volatile] type variableName [= value];
限定访问修饰符
  • public:公共变量,可以被任意的类和方法使用。
  • protected:受保护的变量,可以被自己的子类和同一个包中的类或方法访问。
  • 空白访问修饰符:即不加任何修饰符,只能被同一个包中的类访问。
  • prvate:私有变量,只能在当前类中使用。其他类无法使用,这种类所需的访问权限最高,是最安全的变量,因为只能被当前类使用,不能被外界访问,因此可以实现信息的隐藏,从而保证了我们所讲的封装性。

  可以看出,上边的访问修饰符,由上到下所需的访问权限是逐级增高的。

  (注:这里的访问权限,举个例子,对于一栋办公大楼,其公共休息区所有人都可以随意进入,所以访问权限最低,而存放机要档案的房间只能最高领导进入,普通人无法访问,所需的访问权限最高)

实例变量和类变量–static关键字

  static修饰的变量称为类变量,没有static修饰的变量称为实例变量。实例变量和类变量的区别是:

  • 实例变量是属于一个对象(实例)的,而类变量是属于一个类的。
  • 实例变量在其对应的对象中有属于自己的内存空间,类变量相当于多个对象共享一块空间
  • 实例变量仅能通过实例来访问,而类变量可以通过类访问,也可以通过实例访问,但实际上,类变量通过实例访问时,编译器首先根据实例找到其对应的类,然后通过类访问的,本质上类变量依旧是通过类访问的。
type variableName

  成员变量可以任意已知的Java数据类型,包括用户自定义的类类型,变量的命名通常使用小驼峰命名法(即首单词的首字母小写),成员变量的作用域为整个类,类中所有的方法都可以访问成员变量。

final关键字

  final修饰的变量叫最终变量,也为标识符常量。常量可以在声明时赋初值,也可以在后面赋值,常量一旦赋值,其值就不能改变了。

volatile关键字

  由该关键字修饰的成员变量称为共享变量,在多线程程序中,共享变量可以被异步修改。(本文不做讨论)

成员方法的定义

  成员方法的定义包括方法的声明和方法体的定义,其格式一般如下:

[public|protected|private][static][final|abstract][native][synchronized] returnType methodName([paramList])[throws ExceptionList]{
	method body;
}
限定访问修饰符

  成员方法的限定访问修饰符和成员变量的限定访问修饰符含义一样,不再过多介绍。

类方法和实例方法–static关键字

  同类变量和实例变量一样,由static修饰的方法称为类方法,没有该关键字修饰的称为实例方法,实例方法只能通过实例调用,类方法既可以通过实例调用也可以通过类调用,但通过实例调用的本质上依旧是通过类调用的。

finalabstract方法

  同成员变量一样,由final修饰的方法为最终方法,最终方法不能重写,但是可以重载,方法的重写与继承有关,将在继承部分详细讨论。

  abstract修饰的方法为抽象方法,如果某个类定义了抽象方法,那么该类必须为抽象类,由于抽象类不能被实例化,所以抽象类必须被继承,继承后抽象方法也必须被重写。

本地方法–native

  native修饰的方法称为本地方法,本地方法是用来的调用由其他语言编写的函数/方法的。

  本地方法是由其他语言(如C、C++ 或其他汇编语言)编写,编译成和处理器相关的代码。本地方法保存在动态连接库中,格式是各个平台专用的,运行中的java程序调用本地方法时,虚拟机装载包含这个本地方法的动态库,并调用这个方法。

同步方法–synchronized

  synchronized修饰的方法称为同步方法,同步方法主要用于多线程程序。(本文不做讨论)

说明

  为了保证封装性,在定义成员变量和方法的时候,尽量使用private级别的变量或方法,当该种变量或方法不能满足要求时,再逐步降低权限,而public修饰的成员变量和方法应是最后考虑的,能不使用则尽量不去使用。

对象的创建

  和一般的变量一样,对象的定义格式如下:

TypeName objecetName = new TypeName();

  例如:创建一个猫的实例:

Cat cat1 = new Cat();

  在上述代码中,=的右边创建了一个对象,然后把地址返回传给了objectName,即objectName中存放的是一个地址,该地址指向的对象类型是TypeName

对象的初始化

默认初始化

  在创建类时,仅声明成员名称,不为其赋值,系统会根据不同的变量为其赋初值。其规则如下:

  • 整型(byteintshortlong):0
  • 浮点型(floatdouble):0.0
  • 布尔型(boolean):false
  • 字符型(char):\u0000
  • 引用类型(例如String):null

  例如:声明一个猫类,声明成员变量时,不赋初值,输出其值。

public class Cat {
    public int age;
    public double height;
    public char sex;
    public String name;
}

  创建一个猫的实例,其初值如下:
在这里插入图片描述

就地初始化

  就地初始化即为在声明类的成员变量的同时为其赋初值。例如:

public class Cat {
    public int age = 2;
    public double height = 10.5;
    public char sex = '母';
    public String name = "胖橘";
}

  创建猫的实例:

public class Main {
    public static  void main(String[] args){
        Cat cat = new Cat();
        System.out.println("猫的年龄:" + cat.age);
        System.out.println("猫的体重:" + cat.height);
        System.out.println("猫的性别:" + cat.sex);
        System.out.println("猫的名字:" + cat.name);
    }
}

  其默认的初值为:
在这里插入图片描述

代码块初始化

  有时候,在声明类的时候,也会使用代码块,在创建变量时,使用代码块完成对变量的初始化。
例如:

public class Cat {
    public int age;
    public double height;
    public char sex;
    public String name;
    {
        age = 3;
        height = 10.7;
        sex = '公';
        name = "小花";
    }
}

  和就地初始化创建的猫咪实例一样,其结果输出为:
在这里插入图片描述

static修饰的代码块

  static修饰的代码块同样也可以用于初始化成员,其具有如下特性:

  • 只能初始化类成员,即由static修饰的成员,不能初始化对象成员(否则会编译出错)。
  • static修饰的代码块只在类加载的时候执行一次,创建对象的时候不执行。
  • 无论static修饰的代码块位于类中的哪个位置,其始终优于普通代码块先执行。
  • 类加载始终是在创建实例之前的。
    例如:
public class Cat {
    public int age;
    public double height;
    public char sex;
    public String name;
    public static  int eye;
    {
        System.out.println("这是普通的代码块!");
        age = 3;
        height = 10.7;
        sex = '公';
        name = "小花";
    }
    static {
        System.out.println("这是static修饰的代码块");
        eye = 2;
    }
}

  为说明static修饰的代码块执行的顺序,特地将其顺序放置在普通代码块之后,同时为说明该代码块仅在类加载的时候执行一次,创建对象的时候不执行,创建两个猫的实例:

public class Main {
    public static  void main(String[] args){
        Cat cat1 = new Cat();
        System.out.println("猫1的年龄:" + cat1.age);
        System.out.println("猫1的体重:" + cat1.height);
        System.out.println("猫1的性别:" + cat1.sex);
        System.out.println("猫1的名字:" + cat1.name);
        Cat cat2 = new Cat();
        System.out.println("猫2的年龄:" + cat2.age);
        System.out.println("猫2的体重:" + cat2.height);
        System.out.println("猫2的性别:" + cat2.sex);
        System.out.println("猫2的名字:" + cat2.name);
    }
}

程序运行结果为:
在这里插入图片描述
  可以看到,static代码块确实只执行了一次,并且优先于普通代码块执行。

  成员的定义实例变量和类变量一节中说过,类变量可以通过类访问,也可以通过成员访问,但通过成员的访问本质上还是通过类访问的,也可以理解为类变量是多个对象共享同一块空间,此处用上述的例子进行验证:

public class Main {
    public static  void main(String[] args){
        Cat cat1 = new Cat();
        Cat cat2 = new Cat();
        System.out.println("这是通过Cat类进行访问的eye变量:" + Cat.eye);
        System.out.println("这是通过cat1进行访问的eye变量:" + cat1.eye);
        System.out.println("这是通过cat2进行访问的eye变量:" + cat2.eye);
        Cat.eye = 3;
        System.out.println("修改后的eye:");
        System.out.println("这是通过Cat类进行访问的eye变量:" + Cat.eye);
        System.out.println("这是通过cat1进行访问的eye变量:" + cat1.eye);
        System.out.println("这是通过cat2进行访问的eye变量:" + cat2.eye);
    }
}

  程序的运行结果如下:在这里插入图片描述
  可以看出,运行结果符合我们的描述。

构造方法初始化

  构造方法是实例初始化的另一种方式,构造方法的方法名和类名一致,其不需要返回值类型,内部也不需要写return语句,同样的构造方法不需要显示的调用,在创建对象时自动被调用,构造方法和其他的一般方法一样,支持重载。

  例如:

public class Cat {
    public int age;
    public double height;
    public char sex;
    public String name;
    public static  int eye;
    
    public Cat(){
        age = 10;
        height = 6.7;
    }
    public Cat(String name,int age){
        this.name = name;
        this.age = age;
    }
}

  上述的两段代码即为两个构造方法,其中一个没有参数,一个含有参数,对于无参数的构造方法,创建对象时不传入参数,而有参数的构造方法创建对象时必须传入对应类型的参数。
例如:

public class Main {
    public static  void main(String[] args){
        Cat cat1 = new Cat();
        Cat cat2 = new Cat("小黑",5);
        System.out.println("猫1的年龄:" + cat1.age);
        System.out.println("猫1的体重:" + cat1.height);
        System.out.println("猫1的性别:" + cat1.sex);
        System.out.println("猫1的名字:" + cat1.name);
        System.out.println("猫2的年龄:" + cat2.age);
        System.out.println("猫2的体重:" + cat2.height);
        System.out.println("猫2的性别:" + cat2.sex);
        System.out.println("猫2的名字:" + cat2.name);
    }
}

程序的运行结果如下:
在这里插入图片描述
  两个猫咪则按照其对应的构造方法进行初始化。

this关键字

  在上边的含有参数的构造方法中,使用了this关键字,可以看出,该构造方法中形参的名字与我们上边定义得到成员变量名字一致了,为了以示区分,我们在方法内部使用this关键字表示是成员变量。
  this关键字的含义:

  • 获取到当前对象的引用,即this中存放的是当前对象的地址。
  • 指向的类型就是当前类的类型。
  • this的引用指向是不能修改的(也就是只能指向当前的对象)。
  • this不能是null
  • this是与对象相关的引用,而static修饰的代码块或方法是类相关的,所以无法在类方法和static修饰的代码块中使用。

创建实例后初识化

  和普通的变量一样,也可以在创建实例后对其变量进行初始化。

公有成员变量的初始化

  对于公有变量的初始化,可直接通过其引用对其初始化,例如:

public class Cat {
    public int age;
    public double height;
    public char sex;
    public String name;
    public static int eye;
}

  创建猫咪实例后为其初始化:

public class Main {
    public static  void main(String[] args){
        Cat cat1 = new Cat();
        cat1.age = 3;
        cat1.name = "小红";
        cat1.height = 3.6;
        cat1.sex = '公';
        System.out.println("猫1的年龄:" + cat1.age);
        System.out.println("猫1的体重:" + cat1.height);
        System.out.println("猫1的性别:" + cat1.sex);
        System.out.println("猫1的名字:" + cat1.name);
    }
}

程序运行的结果为:
在这里插入图片描述

私有成员变量的初始化

  对于私有变量,即由private修饰的变量,因为其只能在当前类中使用,无法被其他类使用,所以需要使用方法来对其进行访问修改。例如:

public class Cat {
    private int age;
    //获取age的信息
    public int getAge(){
        return age;
    }
	//修改age的信息
    public void setAge(int age) {
        this.age = age;
    }
}

  如上所示,我们可以定义一组方法,创建对象后,通过对象的引用访问这两个方法,用来获取和修改私有成员age的信息,这种方式,我们形象的将其称为“setter”和“getter”方法。

  使用方式如下:

public class Main {
    public static  void main(String[] args){
        Cat cat1 = new Cat();
        System.out.println("获取cat1的age:" + cat1.getAge());
        System.out.println("修改age:");
        cat1.setAge(5);
        System.out.println("修改后cat1的age:" + cat1.getAge());
    }
}

程序运行结果如下:
在这里插入图片描述

初始化的顺序

  在一个类中,大多数时候并不是只有一种初始化方式,而是有多种初始化在一起,当有多种初始化时,他们的执行顺序如下:

  首先执行静态代码块(static)修饰的,无论该代码块位于类中的何处位置,然后执行就地初始化和普通代码块,这两者按照在程序出现的顺序顺次执行,最后执行构造方法里的代码块,同样的无论构造方法代码块位于程序哪里,都在最后执行。

  上述初始化执行完毕后,才是手动初始化(即在主程序中通过“setter”和“getter”等方式初始化)。例如:

public class Cat {
    public Cat(){
        System.out.println("这是构造方法的代码块,这段代码位于类的最开头");
    }
    int a =retInt();
    {
        System.out.println("这是普通代码块1");
    }
    int b =retInt1();
    {
        System.out.println("这是普通代码块2");
    }
    static {
        System.out.println("这是静态代码块,这段代码位于普通代码块和就地初始化代码块的下边");
    }
    public int retInt(){
        System.out.println("这模仿的是就地初始化1");
        return 0;
    }
    public int retInt1(){
        System.out.println("这模仿的是就地初始化2");
        return 0;
    }
}

  程序的结果如下,符合我们所说的顺序:在这里插入图片描述

  随着代码的不断书写,代码逐渐增多,类也逐渐增多,为了便于存储和管理,我们可以将类分门别类的放入不同的文件夹下,而这一个一个文件夹对应的就是包。

  导入包的命令如下:

import packageName;

  常见的系统包及其功能如下:

  • java.lang:包括了系统常用的基础类StringObject等,当打开Java的JVM时,此包自动加载。
  • java.lang.reflect:Java反射编程包
  • java.net:Java网络编程包
  • java.sql:数据库开发支持包
  • java.util:Java提供的工具程序包

toString方法

  toString方法用于返回反映对象的字符串,该方法是Object自带的方法,一个类未指定父类,则表示继承Object类,自然也会继承该类的方法,一个类指定了父类,它的父类继承了该方法,所以它也会从父类继承该方法,但是由系统提供的该方法返回的是对象所在的包、类名以及对应的散列(又称哈希)码。调用cat1toString方法后结果如下:
在这里插入图片描述
  但通常我们想要得到的是该对象的一些具体信息,例如猫咪对象中,猫咪的名称,性别,年龄等,因此我们需要对该方法进行重写。代码如下:

public class Cat {
    public int age;
    public double height;
    public char sex;
    public String name;
    public static int eye;

    @Override
    public String toString() {
        return "Cat{" +
                "age=" + age +
                ", height=" + height +
                ", sex=" + sex +
                ", name='" + name + '\'' +
                '}';
    }
}

创建猫咪类,并进行初始化,再次调用该方法:

public class Main {
    public static  void main(String[] args){
        Cat cat1 = new Cat();
        cat1.age = 3;
        cat1.name = "小红";
        cat1.height = 3.6;
        cat1.sex = '公';
        System.out.println(cat1.toString());
    }
}

其结果如下:
在这里插入图片描述

总结

  以上则是关于面向对象中类和对象创建的一些基本语法和注意事项,后边将重点介绍前述面向对象的三种重要特性。(未完待续……)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值