面向对象-万物皆对象
尽管Java是基于C++的,但是相比之下,Java是一种更加“纯粹”的面向对象程序设计语言。在使用Java进行设计之前,我们需要将思想转换到面向对象的世界中来。
- 用引用操纵对象
在Java中,一切被视为对象,操作的标识符可以看做是对对象的一个“引用”。
例如:遥控器可以操纵电视,那么我们可以将遥控器看作是一个引用,把对象看作是一个对象,我们想要变换频道或者调节音量的时候,只需要操作遥控器(引用)就可以了,那么遥控器(引用)就可以调控电视机(对象)。如果想在房间四处走走,那么我们只需要携带遥控器(引用),而不是电视机(对象)。
另外,即使没有电视机,遥控器也可以独立存在。也就是说,你可以拥有一个引用,但是并不需要有一个对象与它相关联。所以,如果我们想操作一个词语或者句子的话,就可以创建一个String引用了:
String s;
要注意的是,我们这里创建的只是引用,但并不是对象。如果这个时候我们向s发送信息,就会出现运行时的错误。因为s并没有和任何事物相关联。因此,我们一旦创建了这个引用,就希望它可以与对象相关联,通常用new操作符来实现这一目的。new关键字的意思就是“给我一个新的对象”。
String s = new String("miao");
它不仅表示“给我一个新的字符串”,而且通过提供一个初始字符串(JAVA语言的特性:字符串可以用带引号的文本初始化)。给出了怎样产生这个String信息。
对象存储到什么地方
- 寄存器 。这是最快的存储区,它位于不同于其他存储区的地方—处理器内部。但是寄存器的数量极其有限,因此寄存器根据需求进行分配。我们不能直接控制,也不能在程序中感觉到寄存器存在的任何迹象。
- 栈 。位于RAM(随机访问存储器中)中,但是通过栈指针可以从处理器那里获得直接支持。这是一种快速有效的分配存储的方法,仅次于寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。因此某些Java数据存储在堆栈中—特别是对象的引用,但是Java对象并不存储在其中。
- 堆 。一种存储在内存池(也是位于RAM区),用于存放所有的Java对象。堆不同于栈的好处就是:编译器不需要知道存储的数据在堆里面存活多长时间。因此在堆中分配存储有很大的灵活性。当我们需要一个对象的时候,我们只需要用new写出一段简单的代码,当执行这段代码的时候,就会自动在堆中进行存储分配。但是缺点就是用堆进行存储分配和清理比用栈进行存储分配所需要的时间要长。
- 常量存储 。常量值通常存放在程序代码的内部,这样做是安全的,因为他们永远不会改变。有时在嵌入式系统中,常量本身回合其他部分隔离开,因此在这种情况下,可以选择将其存放在ROM(只读存储器)中。
-
非RAM存储 。如果数据完全存活在程序之外,那么它可以不受程序的任何控制,在程序没有运行时也可以存在。其中两个基本的例子就是流对象和持久化对象。在流对象中,对象转换为字节流,通常被发送给另外一台机器。在持久化对象中,对象被存放在磁盘上,因此即使程序终止,它们仍可以保持自己的状态。而这种存储方式的技巧就在于可以把对象转化我存放在其他媒介上的事物,在需要的时候可以恢复为常规的 、基于RAM的对象。Java提供了轻量级持久化的支持。
基本类型
高精度数字
- BigInteger:支持任意精度的整数,在运算中可以准确的表示任意大小的整数而不会丢失任何信息。
- BigDecimal:支持任何精度的定点数。可以用它进行精确的货币运算。
Java中的数组
当创建一个数组对象时,实际上就是创建了一个引用数组,并且每个引用都会自动被初始化一个特定值,该值拥有自己的关键字null。一旦Java看到null,就知道这个引用没有被指向某个对象。在使用任何引用之前必须要为其指定一个对象;如果试图使用一个还是null的引用,在运行的时候就会报错。
- Java数组确保数组会被初始化,而为不能在它的范围之外被访问。
Java永远不需要销毁对象
- Java有一个垃圾回收器,用来监听用new创建的所有对象,并辨别那些不会被再引用的对象。随后,释放这些对象的内存空间,以便供其他新的对象使用。也就是说,我们不必担心内存回收的问题。我们只需要创建对象,一旦不再需要,他们便会自动消失。
- 创建新的数据类型:类
大多数面向程序设计语言习惯用class表示这个类。class关键字之后紧跟着新类型的名字,例如:
class ATypeName {/* Class body */}
引入新类型之后就可以用new来创建这个类型的对象:
ATypeName a = new ATypeName();
- 此时我们只是定义好了一个对象。
字段和方法
类一旦被定义,就可以设置两种类型元素:字段(有时被称为数据成员)和方法(有时被称为成员函数)。
每个对象都有用来存储其字段的空间;普通字段不能在对象之间共享。
class DataOnly {
int a;
double b;
boolean c;
}
这个类除了存储数据之外什么也不能做但是仍然可以像下面那样创建它的一个对象:
DataOnly data = new DataOnly();
可以给字段赋值如下:
data.a = 18;
data.b = 1.1;
data.c = false;
- 注意:DataOnly类除了保存数据之外没有别的用处,因为它没有任何成员方法。
基本成员默认值
当类的某个成员十几本数据类型,即使没有初始化,Java也会确保它获得一个默认值,如下表:
当变量作为类的成员使用的时候,Java猜确保给其默认值,以确保那些是基本类型的成员变量得到初始化,防止程序发生错误(但是我们最好明确的给变量进行初始化)。但是这种初始化的方法并不适用于局部变量。
- 方法、参数和返回值
- 许多编程语言例如C、C++,用函数这个术语来命名子程序,在Java中我们用方法来命名。
方法的基本组成由:名称、参数、返回值和方法体组成。以下是它的基本的形式:
ReturnType methodName(/* Argument list */) {
/* Method body */
}
- 返回类型描述的是在调用方法之后从方法返回的值。参数列表给出了要传给方法的信息的类型和名称。方法名和参数列表唯一标识出某个方法。
- Java中的方法只能作为类的一部分来创建
- 方法只有通过对象才能被调用(static是针对于类存在的,并不依赖于对象存在),并且这个方法必须能够执行这个方法的调用。
- 若视图在某个对象上调用它并不具备的方法,那么编译的时候就会报错。
- 对象调用方法的时候:对象名+ . +方法名和参数列表
objectName.method(arg1,arg2,arg3);
例:有个方法f(),不带任何参数,返回类型是int,如果有个名为a的对象,可以通过它调用f():
`int x = a.f();
返回值类型必须要与x类型相互兼容,这种调用方法的行为通常被称为发送消息给对象。消息是f(),对象是a。面向对象的程序设计通常简单的归纳为“面向对象发送消息”。`
参数列表
在参数列表中必须指定每个所传递对象的类型及名字。像Java任何传递对象的场合一样,这里传递的实际上也是引用,并且引用的类型必须正确。如果参数类型是String类型,则必须传递一个 String对象,否则编译器就会抛出错误。
假设某个方法接受String为其参数,它必须置于某个类的定义内才能被正确编译:
int storage(String s) {
return s.length()*2;
}
参数类型是String,参数名是s。一旦将s传递给此方法,就可以把它当做其他对象一样进行处理(可以给他传递消息)。这里,s的length()方法被调用,它是String类提供的方法之一,会返回字符串包含的字符数。
- return关键字的用法:它包括两方面:
1)它代表“已经做完,离开此方法”
2)如果此方法产生了一个值,这个值要放在return语句后面。(在上面例子中,返回值是通过计算s.length()*2这个表达式得到的)。
构建一个Java程序
运用其它构件
- import指示编译器导入一个包,准确告诉编译器你想要的类是什么。它导入的包也就是一个类库(在其他语言中,一个库不仅包含类,还可能包括方法和数据;但是在Java中所有的代码都必须写在类中)。
- 我们使用与编译器附在一起的Java标准类库里的构件。有了这些构件,就可以写成如下简单代码:
import java.util.ArrayList;
以上代码就是告诉编译器你想使用Java中的ArrayList类。但是,util包含了数量众多的类,我们要想使用几个,同时又不想明确的逐一声明;那么我们很容易使用通配符 “ * ” 来达到这个目的:
import java.util.*;
这种一次导入一群类的方式比逐个导入类的方式更常用。
static关键字
- static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。
- static的关键之处就是方便在没有创建对象的情况下来进行调用(方法/变量)。被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。
- 在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。
- 如果说想在不创建对象的情况下调用某个方法,就可以将这个方法设置为static。我们最常见的static方法就是main方法,因为程序在执行main方法的时候没有创建任何对象。
- 静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
有些面向对象语言采用类数据和类方法两个术语,代表那些数据和方法只是作为在整个类,而不是类的某个特定对象存在。我们只需要将static关键字放在定义之前,就可以将字段或者方法设置为static:
Class StaticTest{
static int i = 47;
}
此时若我们再创建两个StaticTest对象,StaticTest.i也只有一份存储空间,这两个对象共享一个iStaticTest st1 = new StaticTest();
StaticTest st2 = new StaticTest();
上面代码st1.i和st2.i指向同一存储空间,因此他们具有相同的值47。
static特性:只会在类加载的时候执行一次。可以优化程序性能
class Person{
private Date birthDate;
public Person(Date birthDate) {
this.birthDate = birthDate;
}
boolean isBornBoomer() {
Date startDate = Date.valueOf("1900");
Date endDate = Date.valueOf("2000");
return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
}
}
isBornBoomer是用来这个人是否是1900-2000年出生的,而每次isBornBoomer被调用的时候,都会生成startDate和endDate两个对象,造成了空间浪费,如果改成这样效率会更好:
class Person{
private Date birthDate;
private static Date startDate,endDate;
static{
startDate = Date.valueOf("1900");
endDate = Date.valueOf("2000");
}
public Person(Date birthDate) {
this.birthDate = birthDate;
}
boolean isBornBoomer() {
return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
}
}
static不允许修饰局部变量
static的一个重要用法就是在不创建任何对象的前提下就可以调用它
Java程序
类的名字必须和文件名相同。如果创建一个独立运行的程序,那么文件中必须存在某个类与该文件同名(否则,编译就会报错),且那个类必须包含一个名为main()的方法:
public static void main(String[] args)
其中,public关键字意指这是一个可由外部调用的方法,main()方法的参数是一个String对象的数组。在这个程序中没有提到args,但是Java编译器要求必须这样做,因为args要用来存储命令行参数。
下面演示输出打印操作:
System.out.println(new Data());
在此,传递的参数是一个Date对象,一旦创建它之后,就可以直接将它的值(它被自动转换为String类型)发送给println()。当这条语句执行完毕之后,Date对象就不再被使用,而垃圾回收器发现这一情况,并在任意时候将其收回。因此我们没有必要关心怎么去清理它。
编译和运行
首先我们要有一个Java开发环境,在此我们使用Sun公司提供的JDK(Java Developer’s Kit,Java开发人员工具包)开发环境,以便确定怎样开发和运行环境。安装好JDK之后,还需要设定好路径信息,以确保计算机能够找到javac和Java这两个文件。
注释
- 多行注释:
方式一/*this is a comment
*that continues
*across lines
*/
方式二/*this is comment that
continues across lines*/- 单行注释:
//this is one-line comment
- 下面是三种类型的注释文档,分别对应于注释位置后面的三种元素:类,域和方法。也就是说,类注释通常位于类定义前面;域注释正好位于域定义之前;而方法注释也正好位于方法定义的前面:
/** A class comment */
public class Documentaction{
/** A file comment */
public int i;
/** A method comment */
public void f() {}
}
上一篇: 前端性能优化