同步操作将从 turnon/blog 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
title: Java 面向对象
date: 2020-08-06 18:20:39
categories:
- Java
- JavaSE
- 基础特性
tags:
- Java
- JavaSE
- 面向对象
permalink: /pages/3e1661/
在Java 基本数据类型 中我们了解 Java 中支持的基本数据类型(值类型)。本文开始讲解 Java 中重要的引用类型——类。
每种编程语言,都有自己的操纵内存中元素的方式。
Java 中提供了基本数据类型,但这还不能满足编写程序时,需要抽象更加复杂数据类型的需要。因此,Java 中,允许开发者通过类(类的机制下面会讲到)创建自定义类型。
有了自定义类型,那么数据类型自然会千变万化,所以,必须要有一定的机制,使得它们仍然保持一些必要的、通用的特性。
Java 世界有一句名言:一切皆为对象。这句话,你可能第一天学 Java 时,就听过了。这不仅仅是一句口号,也体现在 Java 的设计上。
Object
类(从这个名字,就可见一斑)。new
创建对象(基本数据类型、String、枚举特殊处理),对象存储在堆中。// 下面两
String s = "abc";
String s = new String("abc");
其中,String s
定义了一个名为 s 的引用,它指向一个 String
类型的对象,而实际的对象是 “abc”
字符串。这就像是,使用遥控器(引用)来操纵电视机(对象)。
与 C/C++ 这类语言不同,程序员只需要通过 new
创建一个对象,但不必负责销毁或结束一个对象。负责运行 Java 程序的 Java 虚拟机有一个垃圾回收器,它会监视 new
创建的对象,一旦发现对象不再被引用,则会释放对象的内存空间。
封装(Encapsulation)是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。
封装最主要的作用在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。
封装的优点:
实现封装的步骤:
继承是 java 面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
现实中的例子:
狗和鸟都是动物。如果将狗、鸟作为类,它们可以继承动物类。
类的继承形式:
class 父类 {}
class 子类 extends 父类 {}
继承可以使用 extends
和 implements
这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object
,当一个类没有继承的两个关键字,则默认继承 Object
(这个类在 java.lang
包中,所以不需要 import
)祖先类。
刚开始学习面向对象编程时,容易被各种术语弄得云里雾里。所以,很多人会死记硬背书中对于术语的定义。
但是,随着应用和理解的深入,应该会渐渐有更进一步的认识,将其融汇贯通的理解。
学习类之前,先让我们思考一个问题:Java 中为什么要引入类机制,设计的初衷是什么?
Java 中提供的基本数据类型,只能表示单一的数值,这用于数值计算,还 OK。但是,如果要抽象模拟现实中更复杂的事物,则无法做到。
试想,如果要让你抽象狗的数据模型,怎么做?狗有眼耳口鼻等器官,有腿,狗有大小,毛色,这些都是它的状态,狗会跑、会叫、会吃东西,这些是它的行为。
类的引入,就是为了抽象这种相对复杂的事物。
对象是用于计算机语言对问题域中事物的描述。对象通过方法和属性来分别描述事物所具有的行为和状态。
类是用于描述同一类的对象的一个抽象的概念,类中定义了这一类对象所具有的行为和状态。
类可以看成是创建 Java 对象的模板。
什么是方法?扩展阅读:面向对象编程的弊端是什么? - invalid s 的回答
与大多数面向对象编程语言一样,Java 使用 class
(类)关键字来表示自定义类型。自定义类型是为了更容易抽象现实事物。
在一个类中,可以设置一静一动两种元素:属性(静)和方法(动)。
类的形式如下:
修饰符 返回值类型 方法名(参数类型 参数名){
...
方法体
...
return 返回值;
}
方法包含一个方法头和一个方法体。下面是一个方法的所有部分:
示例:
public static int add(int x, int y) {
return x + y;
}
Java 支持两种调用方法的方式,根据方法是否返回值来选择。
当程序调用一个方法时,程序的控制权交给了被调用的方法。当被调用方法的返回语句执行或者到达方法体闭括号时候交还控制权给程序。
当方法返回一个值的时候,方法调用通常被当做一个值。例如:
int larger = max(30, 40);
如果方法返回值是 void,方法调用一定是一条语句。例如,方法 println 返回 void。下面的调用是个语句:
System.out.println("Hello World");
每个类都有构造方法。如果没有显式地为类定义任何构造方法,Java 编译器将会为该类提供一个默认构造方法。
在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名,一个类可以有多个构造方法。
public class Puppy{
public Puppy(){
}
public Puppy(String name){
// 这个构造器仅有一个参数:name
}
}
Java 支持的变量类型有:
局部变量
- 类方法中的变量。实例变量(也叫成员变量)
- 类方法外的变量,不过没有 static
修饰。类变量(也叫静态变量)
- 类方法外的变量,用 static
修饰。特性对比:
局部变量 | 实例变量(也叫成员变量) | 类变量(也叫静态变量) |
---|---|---|
局部变量声明在方法、构造方法或者语句块中。 | 实例变量声明在方法、构造方法和语句块之外。 | 类变量声明在方法、构造方法和语句块之外。并且以 static 修饰。 |
局部变量在方法、构造方法、或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁。 | 实例变量在对象创建的时候创建,在对象被销毁的时候销毁。 | 类变量在第一次被访问时创建,在程序结束时销毁。 |
局部变量没有默认值,所以必须经过初始化,才可以使用。 | 实例变量具有默认值。数值型变量的默认值是 0,布尔型变量的默认值是 false,引用类型变量的默认值是 null。变量的值可以在声明时指定,也可以在构造方法中指定。 | 类变量具有默认值。数值型变量的默认值是 0,布尔型变量的默认值是 false,引用类型变量的默认值是 null。变量的值可以在声明时指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化。 |
对于局部变量,如果是基本类型,会把值直接存储在栈;如果是引用类型,会把其对象存储在堆,而把这个对象的引用(指针)存储在栈。 | 实例变量存储在堆。 | 类变量存储在静态存储区。 |
访问修饰符不能用于局部变量。 | 访问修饰符可以用于实例变量。 | 访问修饰符可以用于类变量。 |
局部变量只在声明它的方法、构造方法或者语句块中可见。 | 实例变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把实例变量设为私有。通过使用访问修饰符可以使实例变量对子类可见。 | 与实例变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为 public 类型。 |
实例变量可以直接通过变量名访问。但在静态方法以及其他类中,就应该使用完全限定名:ObejectReference.VariableName。 | 静态变量可以通过:ClassName.VariableName 的方式访问。 | |
无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。 | ||
类变量除了被声明为常量外很少使用。 |
对象是根据类创建的。在 Java 中,使用关键字 new 来创建一个新的对象。创建对象需要以下三步:
public class Puppy{
public Puppy(String name){
//这个构造器仅有一个参数:name
System.out.println("小狗的名字是 : " + name );
}
public static void main(String[] args){
// 下面的语句将创建一个Puppy对象
Puppy myPuppy = new Puppy( "tommy" );
}
}
/* 实例化对象 */
ObjectReference = new Constructor();
/* 访问类中的变量 */
ObjectReference.variableName;
/* 访问类中的方法 */
ObjectReference.methodName();
当编译一个 .java 文件时,在 .java 文件中的每个类都会输出一个与类同名的 .class 文件。
MultiClassDemo.java 示例:
class MultiClass1 {}
class MultiClass2 {}
class MultiClass3 {}
public class MultiClassDemo {}
执行 javac MultiClassDemo.java
命令,本地会生成 MultiClass1.class、MultiClass2.class、MultiClass3.class、MultiClassDemo.class 四个文件。
Java 可运行程序是由一组 .class 文件打包并压缩成的一个 .jar 文件。Java 解释器负责这些文件的查找、装载和解释。Java 类库实际上是一组类文件(.java 文件)。
程序一般不止一个人编写,会调用系统提供的代码、第三方库中的代码、项目中其他人写的代码等,不同的人因为不同的目的可能定义同样的类名/接口名,这就是命名冲突。
Java 中为了解决命名冲突问题,提供了包(package
)和导入(import
)机制。
包(package
)的原则:
.
分隔,表示层次结构。.
替换为文件分隔符(反斜杠 /
),通过这个路径名称去查找 Java 类。同一个包下的类之间互相引用是不需要包名的,可以直接使用。但如果类不在同一个包内,则必须要知道其所在的包,使用有两种方式:
通过类的完全限定名示例:
public class PackageDemo {
public static void main (String[]args){
System.out.println(new java.util.Date());
System.out.println(new java.util.Date());
}
}
通过 import
导入其它包的类到当前类:
import java.util.Date;
public class PackageDemo2 {
public static void main(String[] args) {
System.out.println(new Date());
System.out.println(new Date());
}
}
说明:以上两个示例比较起来,显然是
import
方式,代码更加整洁。
访问权限控制的等级,从最大权限到最小权限依次为:
public > protected > 包访问权限(没有任何关键字)> private
public
- 表示任何类都可以访问;包访问权限
- 包访问权限,没有任何关键字。它表示当前包中的所有其他类都可以访问,但是其它包的类无法访问。protected
- 表示子类可以访问,此外,同一个包内的其他类也可以访问,即使这些类不是子类。private
- 表示其它任何类都无法访问。接口是对行为的抽象,它是抽象方法的集合,利用接口可以达到 API 定义和实现分离的目的。
接口,不能实例化;不能包含任何非常量成员,任何 field 都是隐含着 public static final
的意义;同时,没有非静态方法实现,也就是说要么是抽象方法,要么是静态方法。
Java 标准类库中,定义了非常多的接口,比如 java.util.List
。
public interface Comparable<T> {
public int compareTo(T o);
}
抽象类是不能实例化的类,用 abstract
关键字修饰 class
,其目的主要是代码重用。除了不能实例化,形式上和一般的 Java 类并没有太大区别,可以有一个或者多个抽象方法,也可以没有抽象方法。抽象类大多用于抽取相关 Java 类的共用方法实现或者是共同成员变量,然后通过继承的方式达到代码复用的目的。
Java 标准库中,比如 collection
框架,很多通用部分就被抽取成为抽象类,例如 java.util.AbstractList
。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。