2023年将会持续于B站、CSDN等各大平台更新,可加入粉丝群与博主交流:838681355,为了老板大G共同努力。
【商务合作请私信或进群联系群主】
1.一个简单的JAVA应用程序了解
2.注释
3.数据类型
4.变量与常量
5.运算符
6.字符串
7.输入输出
8.控制流
9.大数
10.数组
1.新建项目,文件名为类名,如下应为FirstSample.java
public class FirstSample
{
public static void main(String[] args)
{
System.out.println("We will not use 'hello,world!'"); //System.out对象调用println方法输出
}
}
在一个 Java 程序中,总能找到一个类似的定义:
public class Hello {
...
}
该定义被称为 class(类):
Hello
:类名,大小写敏感。{}
中间是类的定义。2.每个JAVA应用程序兜必须有一个main方法,声明格式如下:
public class ClassName
{
public static void main(String[] args)
{
program statements //通用语法object.method(parameters)等同于函数调用
}
}
* System.out.println()输出之后自动换行,而System.out.print()输出之后不换行 *
方法是可执行的代码块,一个方法包括以下内容:
main()
:方法名(方法参数)
(上例的 main
方法有一个参数,参数类型是 String[]
)args
,public
、static
:参数名,用来修饰方法(上例表示它是一个公开的静态方法)void
:方法的返回类型{}
中间的就是方法的代码方法的代码每一行用 ;
结束:
// 作用是打印一个字符串到屏幕上
System.out.println("Hello, world!");
Java 规定,某个类定义的 public static void main(String[] args)
是 Java 程序的固定入口方法,因此,Java 程序总是从 main
方法开始执行。
最后,当把代码保存为文件时,文件名必须是 Hello.java
,而且文件名也要注意大小写,因为要和定义的类名 Hello 完全保持一致。
// 在一行内注释 (“//”是注释得开始,行尾表示注释结束。)
/ *一行或多行得注释*/ (“/*”是注释得开始,以“*/”结束。)
/**文档注释*/ (以“/**”开头,以“*/结束)
概念:标识符是由字母、数字、下划线(_)或美元符($) 组成得字符串,数字不能作为标识符得开头,标识符不能含有其他符号,例如+、=、*、%等,也不允许插入空白。
正确:User_name _sys_varl $ changesizeof
错误:2Sun class #myname
java数据类型共有8种基本类型,4种整形,2种浮点类型,1种字符类型,1种用于真值类型
整形(byte、short、int、long)
浮点型(float、double)
字符型(char)
真值类型(布尔boolean)
整数用于没有小数部分的数值,允许是负数。
int 4字节
short 2字节
long 8字节
byte 1字节
浮点类型用于表示有小数部分的数值。
float 4字节
double 8字节
表示单个字符,如今有些Unicode字符可以用一个char描述。
boolean类型有两个值:false和true,用来判断逻辑条件。整形和布尔值之间不能进行随意转换。
变量用于存储值,常量是值不变的变量。
每个变量有一个类型(type),声明变量时需要指定变量类型,例:
double salary;
int vacationDays;
long earthPopulation;
boolen done;
对一个声明过的变量进行复制:
int vacationDays;
vacationDays = 12;
可以将变量声明和初始化放置同一行:
int vacationDays = 12;
关键字final指示常量:表示这个变量只能被赋值一次,一旦被赋值就无法更改,例:
public class FirstSample
{
public static void main(String[] args)
{
final double CM_PER_INCH = 2.54;
double paperWidth = 8.5;
double paperHeight = 11;
System.out.println("Paper size in centimeters:"
+paperWidth * CM_PER_INCH + "by " + paperHeight * CM_PER_INCH);
}
}
关键字static final设置一个类常量,例:
public class FirstSample
{
public static final double CM_PER_INCH = 2.54;
public static void main(String[] args)
{
double paperWidth = 8.5;
double paperHeight = 11;
System.out.println("Paper size in centimeters: "
+ paperWidth * CM_PER_INCH + " by " + paperHeight * CM_PER_INCH);
}
}
自定义枚举类型,枚举类型包括有限个命名的值,例:
enum Size { SMALL, MEDIUM, LARGE, EXTRA_LARGE };
然后接着声明这种类型的变量:
Size s = Size.MEDIUM;
1.算术运算符:+、-、*、/、% ,此外还有“++”和“--”,分为加1和减1运算符,前者表示加1操作,后者表示减1操作。
2.关系运算符:>、<、>=、<= 、==(等于)、!=(不等于)
3.逻辑运算符:&&(与)、||(或)、!(非),前两个为二元运算符、后者为一元运算符
4.位运算符:取反( ~ )、按位与(&)、按位或( | )、异或(^)、右移(>>),左移(<<),无符号右移(>>>)
5. 其他运算符:拓展赋值运算符(+=、-=、*=、/=、%=、&=、|=、……=、>>=、<<=和>>>=)、条件运算符(?:)、点运算符(.)、实例运算符(instan-ceof)、new运算符及数组下标运算符(【 】)等
double x = 9.9973;
int nx = (int)x; => 强转后nx = 9
double x = 9.997;
int nx = (int) Math.round(x) => 四舍五入 nx = 10
x += 4; 等同于 x = x+4; (一般来说,要把运算符放在=号左边,*=或%=)
自增运算符: n++将变量n的当前值+1
int n = 12;
n++;
自减运算符: n--将n的值-1
int n = 12;
n--;
检测相等性,可以使用两个等号==:
3 == 7; 值为flase
检测不相等,使用!=;
3 != 7; 值为true
&& 优先级比 || 高,例:
a && b || c 等同于 (a && b) || c
+=是右结合运算符,例如:
a += b += c 等同于 a += (b += c)
优先级 运算符 运算符说明
1 . [] () {} , ; 分隔符
2 ++ -- ~ ! 单目运算符
3 (type) 强制类型转换运算符
4 * / % 乘法、除法、求余
5 + - 加法、减法
6 << >> >>> 移位运算符
7 < <= > >= instanceof 关系运算符
8 == != 等价运算符
9 & 按位与
10 ^ 按位异或
11 | 按位或
12 && 条件与
13 || 条件或
14 ? : 三目运算符
15 = += -= *= /= &= |= ^= %= <<= >>= >>>= 赋值
String e = ""; //an empty string
String greeting = "Hello";
String类的substring方法可以从一个较大的字符串提取出一个子串。例如:
String greeting = "Hello";
String s = greeting.substring(0,3); => 创建了一个字符串"Hel"
substring的工作方式优点:容易计算子串的长度。字符串s.substring(a,b)的长度为b-a。
java语言允许使用+号连接(拼接)两个字符串:
String expletive = "Expletive";
String PG13 = "deleted";
String message = expletive + PG13;
用于输出语句:
System.out.println("The answare is "+answer);
需要把多个字符串放在一起,用一个界定符分隔,可以使用join静态方法:
String all = String.join("/","S","M","L","XL"); // 输出 S/M/L/XL
在JAVA11中,提供了一个repeat方法:
String repeated = "java".repeat(3); //repeat is "javajavajava"
public class test {
public static void main(String[] args)
{
String greeting = "Help";
greeting = greeting.substring(0,3) + "p!";
System.out.println(greeting);
}
}
可以使用equals方法检测两个字符串是否相等: s.equals(t)
如果字符串s于字符串t相等,则返回true;否额,返回flase。s与t可以是字符串变量,也可以是字符串字面量: "Hello".equals(greeting)
想要检测两个字符串是否相等,不区分大小写,可以使用equalsIgnoreCase方法: "Hello".equalsIgnoreCase("hello")
//不能使用==运算符检测两个字符串是否相等,这个运算符只能确定两个字符串是否存放在同一个位置上;因为完全有可能将内容像如同的多个字符串副本放置在不同的位置上;
空串""是长度为0的字符串。可以调用代码检查是否为空: if (str.length()==0) 或 if (str.equals(""))
String变量还可以放一个特殊的值,名为null,表示目前没有任何对象与该变量关联:if (str == null)
要检查一个字符串既不是null也不是空串,需要使用: if (str != null && str.length() !=0)
码点: 每一个称为一个点
length方法将返回采用UTF-16编码表示给定字符串所需要的代码单元数量:
String greeting = "Hello";
int n = greeting.length(); //is 5
想要得到实际长度,既码点数量,可以调用:
int cpCount = greeting.codePointCount(0,greeting.length());
调用s.charAt(n) 将返回位置n的代码单元,n介于0~s.length()-1之间,例如:
char first = greeting.charAt(0); //first is 'H'
char last = greeting.CharAt(4); //last is 'o'
想要得到第一个码点:
int index = greeting.offsetByCodePoints(0,i);
int cp = greeting.codePointAt(index);
遍历一个字符串并一次查看每个码点:
int cp = sentence.codePointAt(i);
if (Character.isSupplementaryCodePoint(cp)) i += 2;
else i++;
反向遍历:
i--;
if (Character.isSurrogate(sentence.charAt(i))) i--;
int cp = sentence.codePointAt(i);
JAVA应用编程接口(API),每一个API注释都以类名开始,如:java.lang.String。类名之后是一个或多个方法的名字、解释和参数描述。
java.lang.String
* char charAt(int index):返回给定位置的代码单元。
* int codePointAt(int index):返回从给定位置开始的码点
* int offsetByCodePoints(int startIndex,int cpCount):返回从startIndex码点开始,cpCount个码点后的码点索引
* int compareTo(String other):按照字典顺序,如果字符串位于other之前,返回一个负数;如果位于other后,返回一个正数;如果相等则为0.
* IntStream codePoints():将这个字符串的码点作为一个流返回。调用toArray将它们放在一个数组中。
* new String(int[] codePoints, int offset,int count):用数组中从offset开始的count个码点构造一个字符串
* boolean empty()
* boolean blank():如果字符串为空或者由空格组成,返回true
* boolean equals(Object other):如果字符串与other相等,返回true
* boolean equalsIgnoreCase(String other):如果字符串与other相等(忽略大小写),返回true
* boolean startsWith(String prefix)
* boolean endsWith(String suffix):如果字符串以prefix开头或以suffix或结尾,返回true
* int index0f(String str)
* int index0f(String str,int fromIndex)
* int index0f(int cp)
* int index0f(int cp,int fromIndex):返回与字符串str或码点cp匹配的第一个子串的开始位置,从索引0或fromIndex开始匹配,如果字符串不存在str返回-1.
* int lastIndex0f(String str)
* int lastIndex0f(String str,int fromIndex)
* int lastindex0f(int cp)
* int lastindex0f(int cp,int fromIndex):返回与字符串str或码点cp匹配的最后一个字串的开始位置。从原始字符串末尾或fromIndex开始匹配。
* int length():返回字符串代码单元的个数
* int codePointCount(int startIndex,int endIndex):返回startIndex和endIndex-1之间的码点个数
* String replace(CharSequence oldString,CharSequence newString):返回一个新字符串。这个字符串用newString代替原始字符串中所有oldString。可以用String或StringBuilder对象作为CharSequence参数。
* String substring(int beginIndex)
* String substring(int beginIndex, int endIndex):返回一个新字符串,这个字符串将原始字符串中的大写字母改为小写,或者将原始字符串中所有小写字母改成大写字母
* String trim()
* String strip():返回一个新字符串。这个字符串将删除原始字符串头部和尾部小于等于U+0020的字符(trim)或空格(strip)
* String join(CharSequence delimiter,CharSequence...elements):返回一个新字符串,用给定的定界符连接所有元素
* String repeat(int count):返回一个字符串,将当前字符串重复count次
构建一个空的字符串构建器:
StringBuilder builder = new StringBuilder();
当每次添加一部分内容,就调用append方法:
builder.append(ch); //appends a single character
builder.append(str); //appends a string
构建完成调用toString方法将可以得到一个String对下给你,包含了构建器中的字符序列:
String completedString = builder.toString();
java.lang.StringBuilder
* StringBuilder():构建一个空的字符串构建器
* int length():返回构建器或缓冲器中的代码单元数量
* StringBuilder append(String str):追加一个字符串并返回this
* StringBuilder append(char c):追加一个代码单元并返回this
* StringBuilder appendCodePoint(int cp):追加一个码点,并转换为一个或两个代码单元并返回this
* void setCharAt(int i,char c):将第i个代码单元设置为c
* StringBuilder insert(int offset,String str):在offset位置插入一个字符串并返回this
* StringBuilder insert(int offset,char c):在offset位置插入一个代码单元并返回this
* StringBuilder delete(int startIndex,int endIndex):删除偏移量从startIndex到endIndex-1的代码单元并返回this
* String toString():返回一个与构建器或缓冲器内容相同的字符串
将输出打印到"标准输出流"(控制台窗口),调用System.out.println即可:
System.out.println(str);
读取"标准输入流"System.in可以通过控制台进行输入,需要构造一个与"标准输入流"System.in关联的Scanner对象:
Scanner in = new Scanner(System.in);
示例:
import java.util.*; /* 导入util包 */
public class test {
public static void main(String[] args)
{
Scanner in = new Scanner(System.in); /*标准输入流System.in*/
System.out.print("What is your name?");
String name = in.nextLine(); /* nextline方法是因为输入行中包含空格。 */
System.out.print("How old are you");
int age = in.nextInt(); /* 想读取一个整数就用nextInt,想读取一个浮点数就用nextDouble方法 */
System.out.println("Hello, "+ name +".Next year,you'll be "+(age+1));
}
}
java.util.Scanner
* Scanner(InputStream in):用给定的输入流创建一个Scanner对象
* String nextLine():读取输入的下一行内容
* String next():读取输入的下一个单词(以空格作为分隔符)
* int nextInt():
* double nextDouble():读取并转换下一个表示整数或浮点数的字符序列
* boolean hasNext():检测输入中是否还有其它单词
* boolean hasNextInt()
* boolean hasNextDouble():检测是否还有下一个表示整数或浮点数的字符序列
java.lang.System
* static Console console():如果可以交互,就返回一个Console对象通过控制台窗口与用户交互,否则返回Null。对于任何一个在控制台窗口启动的程序,都可使用Console对象。
java.io.Console
* static char[] readPassword(String prompt, Object... args)
* static StringreadLine(String prompt, Object... args):显示字符串prompt(提示符)并读取用户输入,直到输入行结束。args参数可以用来提供格式参数。
语句System.out.print(x)将数值X输出到控制台,这条命令将以X的类型所允许的最大非0数位个数打印输出X。例:
double x = 10000.0/3.0;
System.out.print(x);
也可以使用printf提供多个参数。例:
System.out.printf("Hello,%s,Next year,you'll be %d",name,age);
f代表浮点数,s表示字符串,d表示十进制整数。
%d 十进制整数
%f 十进制浮点数###
%u 无符号十进制
%o 八进制数
%x 十六进制
%s 字符串
%c 单个字符
%e 指数形式输出
%g 自动选择 %f 格式或 %e 格式中较短的一种输出,且不输出无意义的零
%% 输出百分号
%n 换行 相当于 \n
空格 在正数之前添加空格 | 3333.33|
0 数字前面补0 003333.33
+ 打印正数和负数的符号 +3333.33
- 左对齐(不指定-时,默认为右对齐) |3333.33 |
( 将负数括在括号内 -100 输出为(100)
,(英文逗号) 添加分组分隔符,只对定点浮点数整数部分添加分组分隔符,小数部分不会添加 3,333.33
#(对于f格式) 包含小数点 3,333.
#(对于x或o格式) 添加前缀0x或0 0xcafe
$ 指定要格式化的参数索引。例如,%1 d d %1 dx 将以十进制和十六进制格式打印第1个参数 159 9F
< <格式化前面说明的数值。例如,%d<%x 将以十进制和十六进制打印同一个值 159 9F
可以使用静态String.format方法创建一个格式化的字符串,而不打印输出:
String message = String.format("HellO,%s.Next year,you'll be %d",name,age);
转换符 类型 示例
c 完整的日期和时间 星期五 三月 18 09:34:35 CST 2022
F 年月日 2022-03-18
D 月/日/年 03/18/22
T 24小时时间 09:34:35
r 12小时时间 09:34:35 上午
R 24小时时间,没有秒 09:34
Y 4位数字的年(前面补0) 2022
y 年的后两位数字(前面补0) 22
C 年的前两位数字(前面补0) 20
B 月的完整拼写 三月
b 月的缩写 三月
m 两位数字的月(前面补0) 03
d 两位数字的日(前面补0) 18
e 两位数字的日(前面不补0) 18
A 星期几的完整拼写 星期五
a 星期几的缩写 星期五
j 三位数的年中第几天(前面补0),在001到366之间 077
H 两位数字的小时(前面补0),在0到23之间 09
k 两位数字的小时(前面不补0),在0到23之间 9
I(大写i) 两位数字的小时(前面补0),在01到12之间 09
l(小写L) 两位数字的小时(前面不补0),在1到12之间 9
M 两位数字的分钟(前面补0) 39
S 两位数字的秒(前面补0) 05
L 三位数字的毫秒(前面补0) 920
N 九位数字的毫微秒(前面补0) 920000000
p 上午或下午的标志 上午
z 从 GMT 起,RFC 822 数字位移 +0800
Z 时区 CST
s 从格林尼治时间 1970-01-01 00:00:00 起的秒数 1647567545
Q 从格林尼治时间 1970-01-01 00:00:00 起的毫秒数 164756754592
读取文件,需要构造Scanner对象:(如果文件名包含反斜杠,需要再每个反斜杠加一个额外反斜杠转义:C:\\myadmin\\myfile.txt)
Scanner in = new Scanner(Path.of("myfile.txt"),StandardCharsets.UTF_8);
吸入文件,需要构造PrintWriter对象,需要提供文件名和字符编码:
PrintWriter out = new PrintWriter("myfile.txt",StandardCharsets.UTF_8);
java.util.Scanner
* Scanner(Path p, String encoding):构造一个使用给定字符编码从给定路径读取数据的Scanner
* Scanner(String data):构造一个从给定字符串读取数据的Scanner
java.io.PrintWriter
* PrintWriter(String fileName):构造一个将数据写入文件的PrintWriter。文件名由参数指定
java.nio.file.Path
* static Path of(String pathname):根据给定的路径名构造一个Path
块(复合语句)指由若干条JAVA语句组合的语句,并用一对大括号括起来,块确定了变量的作用域。(但是不能在嵌套的两个块中声明同名变量)
public static void main(String[] args)
{
int n;
...
{
int k;
...
} //k is only defined up to here
}
条件语句形式: if (condition) statement
if (条件表达式) {
语句块;
}
使用块语句形式:
if (yourSales >= target)
{
performance = "Satisfactory";
bouns = 100+0.01 * (yourSales - target);
}
else
{
performance = "Unsatisfactory";
bouns = 0;
}
if (yourSales >= 2 * target)
{
performance = "Excellent";
bouns = 1000;
}
else if (yourSales >= 1.5 * target)
{
performance = "Fine";
bouns = 500;
}
else if (yourSales >= target)
{
performance = "Satisfactory";
bouns = 100;
}
else
{
System.out.println("You're fired");
}
当条件为true,while循环执行一条语句,形式: while (condition) statement
示例:计算需要多长时间才能够存储一定数量退休金
while (balance < goal)
{
balance += payment;
double interest = balance * interestRate / 100;
balance += interest;
years++;
}
System.out.println(years + " years.");
do-while形式: do statement while (condition);
这种循环语句先执行语句,再检测条件循环条件,如果为true,就重复执行语句,然后再次检测循环条件。
do
{
balance += payment;
double interest = balance * interestRate / 100;
balance += interest;
year++;
// print current balance
...
// ask if ready to retire and get input
...
}
while (input.equals("N")); // 用户回答"N",循环就重复执行
for循环语句是支持迭代的一种通用结构。
for(条件表达式1;条件表达式2;条件表达式3) {
语句块;
}
public static void main(String[] args) {
int sum = 0;
for (int i = 1; i < 11; i++) {
sum = sum + i;
}
System.out.println(sum);
}
如果把一个循环放在另一个循环体内,那么就可以形成嵌套循环。
嵌套循环既可以是 for循环嵌套 while 循环,也可以是 while 循环嵌套 do-while 循环 …… 即各种类型的循环都可以作为外层循环,也可以作为内层循环。
当程序遇到嵌套循环时,如果外层循环的循环条件允许,则开始执行外层循环的循环体,而内层循环将被外层循环的循环体来执行——只是内层循环需要反复执行自己的循环体而已。
当内层循环执行结束,且外层循环的循环体执行结束时,则再次计算外层循环的循环条件,决定是否再次开始执行外层循环的循环体。
public static void main(String[] args) {
System.out.println("乘法口诀表:");
// 外层循环
for (int i = 1; i <= 9; i++) {
// 内层循环
for (int j = 1; j <= i; j++) {
System.out.print(j + "*" + i + "=" + j * i + "\t");
}
System.out.println();
}
}
处理多个选项时,可以使用switch语句:
case标签可以是:
* 类型为char、byte、short或int常量表达式
* 枚举常量
例如:包含4个选项的菜单系统
Scanner in = new Scanner(System.in);
System.out.print("Select an option (1,2,3,4) ");
int choice = in.nextInt();
switch (choice)
{
case 1:
...
break;
case 2:
...
break;
case 3:
...
break;
}
return 关键字并不是专门用于结束循环的,return 语句用于终止函数的执行或退出类的方法,并把控制权返回该方法的调用者。如果这个方法带有返回类型,return 语句就必须返回这个类型的值;如果这个方法没有返回值,可以使用没有表达式的 return 语句。
return 语句的一般语法格式如下:
return 与方法相同类型的变量;
如果一个方法使用了 return 语句并且后面跟有该方法返回类型的值,那么调用此方法后,所得到的结果为该方法返回的值。
数组是一种数据结构,用来存储同一类型值的集合。通过一个整型下标(索引)可以访问数组中的每一个值。
例如:
int[] a;
smallPrimes = new int[] {17,19,23,29,31,37};
0~100数组中使用循环访问每个元素。例如:
int[] a = new int[100];
for (int i=0; i<100; i++)
a[i] = i; //fills the array with numbers 0 to 99
如果存在报错,想要获得数组的元素个数,可以使用array.length,例如:
for (int i=0; i<a.length; i++)
System.out.prijntln(a[i]);
依次处理数组中每个元素,不必考虑指定下标值。
这种增强的for循环语句格式为:for (variable : collection) statement
定义一个变量用于暂存集合中每一个元素,并执行响应语句。collection这一集合表达式必须是一个数组或者是一个实现了iterable接口的类对象,例如:
for (int element : a)
System.out.println(element);
两个变量将引用同一个数组:
int[] luckyNumbers = smallPrimes;
luckyNumbers[5]=12; //now smallPrimes[5] is also 12
每一个java应用程序都有一个袋String arg[]参数的main方法,这个main方法将接受一个字符串数组,也就是命令行参数。
例如:
public class Message
{
public static void main(String[] args)
{
if (arg.length ==0 || args[0].equals("-h"))
System.out.print("Hello,");
else if (args[0].equals("-g"))
System.out.print("Goodbye,");
// print the other command-line arguments
for (int i=1; i<args.length; i++)
System.out.print(" "+args[i]);
System.out.println("!");
}
}
当调用这个程序时:java Message -g cruel world就会调用args[0]
要想对数组型数组进行排序,可以使用Arrays类中的sort方法:
int[]a = new int[10000];
...
Arrays.sort(a)
java.util.Arrays
* static String toString(xxx[] a):返回包含a元素的一个字符串,这些元素用中括号包围,并用逗号分隔。在这个方法以及后面的方法中,数组元素类型xxx可以是int、long、char、byte、boolean、float或double
* static xxx[] copy0f(xxx[] a, int end)
* static xxx[] copy0fRange(xxx[] a, int start, int end):返回与a类型相同的一个数组,其长度为length或者end-start,数组元素为a的值,如果end大于a.length,结果会填充0或flase值
* static void sort(xxx[] a):使用优化的快速排序算法对数组进行排序
* static int binarySearch(xxx[] a, xxx v)
* static int binarySearch(xxx[] a, int start, int end, xxx v):使用二分查找算法再有序数组a中查找值v,如果找到v,则返回响应的下表;否则,返回一个负数值r。-r-l是v应插入的位置(为保持a有序)
* static void fill(xxx[] a, xxx v):将数组的所有数据元素设置为v
* static boolean equals(xxx[] a, xxx[] b):如果两个数组大小相同,并且下标相同的元素都对应相等,返回true
声明二维数组:double[][] balances:
初始化:balances = new double[NYEARS][NRATES];
例如:访问元素balances[i][j]
int [][] magicSquare =
{
{16,3,2,13},
{5,10,11,8},
{9,6,7,12},
{4,15,14,1}
};
面向对象简称 OO(Object Oriented),20 世纪 80 年代以后,有了面向对象分析(OOA)、 面向对象设计(OOD)、面向对象程序设计(OOP)等新的系统开发方式模型的研究。
对象的特性:
1. 对象具有属性和行为。
2. 对象具有变化的状态。
3. 对象具有唯一性。
4. 对象都是某个类别的实例。
5. 一切皆为对象,真实世界中的所有事物都可以视为对象。
面向对象优点:
可重用性:代码重复使用,减少代码量,提高开发效率。下面介绍的面向对象的三大核心特性(继承、封装和多态)都围绕这个核心。
可扩展性:指新的功能可以很容易地加入到系统中来,便于软件的修改。
可管理性:能够将功能与数据结合,方便管理。
面向对象具有继承、封装和多态 3 个核心特性:
1. 继承性:程序中的继承性是指子类拥有父类的全部特征和行为,这是类之间的一种关系。Java 只支持单继承.
2. 封装性:封装的目的在于保护信息,优点如下:
a. 保护类中的信息,它可以阻止在外部定义的代码随意访问内部代码和数据。
b. 隐藏细节信息,一些不需要程序员修改和使用的信息,比如取款机中的键盘,用户只需要知道按哪个键实现什么操作就可以,至于它内部是如何运行的,用户不需要知道。
c. 有助于建立各个系统之间的松耦合关系,提高系统的独立性。当一个系统的实现方式发生变化时,只要它的接口不变,就不会影响其他系统的使用。例如 U 盘,不管里面的存储方式怎么改变,只要 U 盘上的 USB 接口不变,就不会影响用户的正常操作。
d. 提高软件的复用率,降低成本。每个系统都是一个相对独立的整体,可以在不同的环境中得到使用。例如,一个 U 盘可以在多台电脑上使用。
3. 多态性:多态性允许一个接口被多个同类使用
类是对象的抽象,对象是类的具体。
类是概念模型,定义对象的所有特性和所需的操作,对象是真实的模型,是一个具体的实体。
类是描述了一组有相同特性(属性)和相同行为(方法)的一组对象的集合。
对象或实体所拥有的特征在类中表示时称为类的属性。
对象执行的操作称为类的方法。
类是构造面向对象程序的基本单位,
定义一个类需要用到class关键字、一个自定义类名、表示程序体括号:
[public][abstract|final]class<class_name>[extends<class_name>][implements<interface_name>] {
// 定义属性部分
<property_type><property1>;
<property_type><property2>;
<property_type><property3>;
…
// 定义方法部分
function1();
function2();
function3();
…
}
public:表示“共有”的意思。如果使用 public 修饰,则可以被其他类和程序访问。每个 Java 程序的主类都必须是 public 类,作为公共工具供其他类和程序使用的类应定义为 public 类。
abstract:如果类被 abstract 修饰,则该类为抽象类,抽象类不能被实例化,但抽象类中可以有抽象方法(使用 abstract 修饰的方法)和具体方法(没有使用 abstract 修饰的方法)。继承该抽象类的所有子类都必须实现该抽象类中的所有抽象方法(除非子类也是抽象类)。
final:如果类被 final 修饰,则不允许被继承。
class:声明类的关键字。
class_name:类的名称。
extends:表示继承其他类。
implements:表示实现某些接口。
property_type:表示成员变量的类型。
property:表示成员变量名称。
function():表示成员方法名称。
示例:
(1) 声明类。编写类的最外层框架,声明一个名称为 Person 的类。
(2) 编写类的属性。类中的数据和方法统称为类成员。其中,类的属性就是类的数据成员。通过在类的主体中定义变量来描述类所具有的特征(属性),这里声明的变量称为类的成员变量。
(3) 编写类的方法。类的方法描述了类所具有的行为,是类的方法成员。可以简单地把方法理解为独立完成某个功能的单元模块。
public class Person {
private String name; // 姓名
private int age; // 年龄
public void tell() {
// 定义说话的方法
System.out.println(name+"今年"+age+"岁!");
}
}
Java 类名的命名规则:
类名应该以下划线(_)或字母开头,最好以字母开头。
第一个字母最好大写,如果类名由多个单词组成,则每个单词的首字母最好都大写。
类名不能为 Java 中的关键字,例如 boolean、this、int 等。
类名不能包含任何嵌入的空格或点号以及除了下划线(_)和美元符号($)字符之外的特殊字符。
在 Java 中类的成员变量定义了类的属性。例如,一个学生类中一般需要有姓名、性别和年龄等属性,这时就需要定义姓名、性别和年龄 3 个属性。声明成员变量的语法如下:
[public|protected|private][static][final]<type><variable_name>
各参数的含义如下。
public、protected、private:用于表示成员变量的访问权限。
static:表示该成员变量为类变量,也称为静态变量。
final:表示将该成员变量声明为常量,其值无法更改。
type:表示变量的类型。
variable_name:表示变量名称。
可以在声明成员变量的同时对其进行初始化,如果声明成员变量时没有对其初始化,则系统会使用默认值初始化成员变量。
整数型(byte、short、int 和 long)的基本类型变量的默认值为 0。
单精度浮点型(float)的基本类型变量的默认值为 0.0f。
双精度浮点型(double)的基本类型变量的默认值为 0.0d。
字符型(char)的基本类型变量的默认值为 “\u0000”。
布尔型的基本类型变量的默认值为 false。
数组引用类型的变量的默认值为 null。如果创建了数组变量的实例,但没有显式地为每个元素赋值,则数组中的元素初始化值采用数组数据类型对应的默认值。
this 关键字是 Java 常用的关键字,可用于任何实例方法内指向当前对象,也可指向对其调用当前方法的对象,或者在需要当前类型对象引用时使用。
大部分时候,普通方法访问其他方法、成员变量时无须使用 this 前缀,但如果方法里有个局部变量和成员变量同名,但程序又需要在该方法里访问这个被覆盖的成员变量,则必须使用 this 前缀。
示例:
假设有一个教师类 Teacher 的定义如下:
public class Teacher {
private String name; // 教师名称
private double salary; // 工资
private int age; // 年龄
}
在上述代码中 name、salary 和 age 的作用域是 private,因此在类外部无法对它们的值进行设置。为了解决这个问题,可以为 Teacher 类添加一个构造方法,然后在构造方法中传递参数进行修改。代码如下:
// 创建构造方法,为上面的3个属性赋初始值
public Teacher(String name,double salary,int age) {
this.name = name; // 设置教师名称
this.salary = salary; // 设置教师工资
this.age = age; // 设置教师年龄
}
在 Teacher 类的构造方法中使用了 this 关键字对属性 name、salary 和 age 赋值,this 表示当前对象。this.name=name语句表示一个赋值语句,等号左边的 this.name 是指当前对象具有的变量 name,等号右边的 name 表示参数传递过来的数值。
this 关键字最大的作用就是让类中一个方法,访问该类里的另一个方法或实例变量。
示例:
/**
* 第一种定义Dog类方法
**/
public class Dog {
// 定义一个jump()方法
public void jump() {
System.out.println("正在执行jump方法");
}
// 定义一个run()方法,run()方法需要借助jump()方法
public void run() {
Dog d = new Dog();
d.jump();
System.out.println("正在执行 run 方法");
}
this 可以代表任何对象,当 this 出现在某个方法体中时,它所代表的对象是不确定的,但它的类型是确定的,它所代表的只能是当前类的实例。只有当这个方法被调用时,它所代表的对象才被确定下来,谁在调用这个方法,this 就代表谁。
}
/**
* 第二种定义Dog类方法
**/
// 定义一个run()方法,run()方法需要借助jump()方法
public void run() {
// 使用this引用调用run()方法的对象
this.jump();
System.out.println("正在执行run方法");
}
this( ) 用来访问本类的构造方法(构造方法是类的一种特殊方法,方法名称和类名相同,没有返回值。详细了解可参考《Java构造方法》一节),括号中可以有参数,如果有参数就是调用指定的有参构造方法。
下面定义一个 Student 类,使用 this( ) 调用构造方法给 name 赋值,Student 类的代码如下所示:
public class Student {
String name;
// 无参构造方法(没有参数的构造方法)
public Student() {
this("张三");
}
// 有参构造方法
public Student(String name) {
this.name = name;
}
// 输出name和age
public void print() {
System.out.println("姓名:" + name);
}
public static void main(String[] args) {
Student stu = new Student();
stu.print();
}
}
对象是对类的实例化。对象具有状态和行为,变量用来表明对象的状态,方法表明对象所具有的行为。Java 对象的生命周期包括创建、使用和清除.
这是常用的创建对象的方法,语法格式如下:
类名 对象名 = new 类名();
在 Java 中,可以使用 java.lang.Class 或者 java.lang.reflect.Constuctor 类的 newlnstance() 实例方法来创建对象,代码格式如下:
java.lang.Class Class 类对象名称 = java.lang.Class.forName(要实例化的类全称);
类名 对象名 = (类名)Class类对象名称.newInstance();
该方法不常用,使用该方法创建对象时,要实例化的类必须继承 java.lang.Cloneable 接口。 调用对象的 clone() 方法创建对象的语法格式如下:
类名对象名 = (类名)已创建好的类对象名.clone();
使用 new 关键字或 Class 对象的 newInstance() 方法创建对象时,都会调用类的构造方法。
使用 Class 类的 newInstance() 方法创建对象时,会调用类的默认构造方法,即无参构造方法。
使用 Object 类的 clone() 方法创建对象时,不会调用类的构造方法,它会创建一个复制的对象,这个对象和原来的对象具有不同的内存地址,但它们的属性值相同。
如果类没有实现 Cloneable 接口,则 clone。方法会抛出 java.lang.CloneNotSupportedException 异常,所以应该让类实现 Cloneable 接口。
示例:
public class Student implements Cloneable {
// 实现 Cloneable 接口
private String Name; // 学生名字
private int age; // 学生年龄
public Student(String name,int age) {
// 构造方法
this.Name = name;
this.age = age;
}
public Student() {
this.Name = "name";
this.age = 0;
}
public String toString() {
return"学生名字:"+Name+",年龄:"+age;
}
public static void main(String[] args)throws Exception {
System.out.println("---------使用 new 关键字创建对象---------");
// 使用new关键字创建对象
Student student1 = new Student("小刘",22);
System.out.println(student1);
System.out.println("-----------调用 java.lang.Class 的 newInstance() 方法创建对象-----------");
// 调用 java.lang.Class 的 newInstance() 方法创建对象
Class c1 = Class.forName("Student");
Student student2 = (Student)c1.newInstance();
System.out.println(student2);
System.out.println("-------------------调用对象的 clone() 方法创建对象----------");
// 调用对象的 clone() 方法创建对象
Student student3 = (Student)student2.clone();
System.out.println(student3);
}
}
除了显式创建对象以外,在 Java 程序中还可以隐含地创建对象,例如下面几种情况。
1)String strName = "strValue",其中的“strValue”就是一个 String 对象,由 Java 虚拟机隐含地创建。
2)字符串的“+”运算符运算的结果为一个新的 String 对象,示例如下:
String str1 = "Hello";
String str2 = "Java";
String str3 = str1+str2; // str3引用一个新的String对象
3)当 Java 虚拟机加载一个类时,会隐含地创建描述这个类的 Class 实例。
创建对象标准格式:类名称 对象名 = new 类名称();
匿名对象就是没有明确的给出名字的对象,是对象的一种简写形式。一般匿名对象只使用一次,而且匿名对象只在堆内存中开辟空间,而不存在栈内存的引用。
示例:
public class Person {
public String name; // 姓名
public int age; // 年龄
// 定义构造方法,为属性初始化
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 获取信息的方法
public void tell() {
System.out.println("姓名:" + name + ",年龄:" + age);
}
public static void main(String[] args) {
new Person("张三", 30).tell(); // 匿名对象
}
}
在 Java 中,要引用对象的属性和行为,需要使用点(.)操作符来访问。对象名在圆点左边,而成员变量或成员方法的名称在圆点的右边。语法格式如下:
对象名.属性(成员变量) // 访问对象的属性
对象名.成员方法名() // 访问对象的方法
在 Java 语言中提供了多个作用域修饰符,其中常用的有 public、private、protected、final、abstract、static、transient 和 volatile,这些修饰符有类修饰符、变量修饰符和方法修饰符.
类的访问控制符只能是空或者 public,方法和属性的访问控制符有 4 个,分别是 public、 private、protected 和 friendly,其中 friendly 是一种没有定义专门的访问控制符的默认情况
通过使用访问控制修饰符来限制对对象私有属性的访问,可以获得 3 个重要的好处。
防止对封装数据的未授权访问。
有助于保证数据完整性。
当类的私有实现细节必须改变时,可以限制发生在整个应用程序中的“连锁反应”。
用 private 修饰的类成员,只能被该类自身的方法访问和修改,而不能被任何其他类(包括该类的子类)访问和引用。因此,private 修饰符具有最高的保护级别。例如,设 PhoneCard 是电话卡类,电话卡都有密码,因此该类有一个密码域,可以把该类的密码域声明为私有成员。
如果一个类没有访问控制符,说明它具有默认的访问控制特性。这种默认的访问控制权规定,该类只能被同一个包中的类访问和引用,而不能被其他包中的类使用,即使其他包中有该类的子类。这种访问特性又称为包访问性(package private)。
同样,类内的成员如果没有访问控制符,也说明它们具有包访问性,或称为友元(friend)。定义在同一个文件夹中的所有类属于一个包,所以前面的程序要把用户自定义的类放在同一个文件夹中(Java 项目默认的包),以便不加修饰符也能运行。
用保护访问控制符 protected 修饰的类成员可以被三种类所访问:该类自身、与它在同一个包中的其他类以及在其他包中的该类的子类。使用 protected 修饰符的主要作用,是允许其他包中它的子类来访问父类的特定属性和方法,否则可以使用默认访问控制符。
当一个类被声明为 public 时,它就具有了被其他包中的类访问的可能性,只要包中的其他类在程序中使用 import 语句引入 public 类,就可以访问和引用这个类。
类中被设定为 public 的方法是这个类对外的接口部分,避免了程序的其他部分直接去操作类内的数据,实际就是数据封装思想的体现。每个 Java 程序的主类都必须是 public 类,也是基于相同的原因。
静态变量和静态方法
使用 static 修饰符修饰的属性(成员变量)称为静态变量,也可以称为类变量,常量称为静态常量,方法称为静态方法或类方法,它们统称为静态成员,归整个类所有。
调用静态成员的语法形式如下:
类名.静态成员
注意:
static 修饰的成员变量和方法,从属于类。
普通变量和方法从属于对象。
静态方法不能调用非静态成员,编译会报错。
类的成员变量可以分为以下两种:
1. 静态变量(或称为类变量),指被 static 修饰的成员变量。
2. 实例变量,指没有被 static 修饰的成员变量。
静态变量与实例变量的区别如下:
1)静态变量
运行时,Java 虚拟机只为静态变量分配一次内存,在加载类的过程中完成静态变量的内存分配。
在类的内部,可以在任何方法内直接访问静态变量。
在其他类中,可以通过类名访问该类中的静态变量。
2)实例变量
每创建一个实例,Java 虚拟机就会为实例变量分配一次内存。
在类的内部,可以在非静态方法中直接访问实例变量。
在本类的静态方法或其他类中则需要通过类的实例对象进行访问。
静态变量在类中的作用如下:
静态变量可以被类的所有实例共享,因此静态变量可以作为实例之间的共享数据,增加实例之间的交互性。
如果类的所有实例都包含一个相同的常量属性,则可以把这个属性定义为静态常量类型,从而节省内存空间。例如,在类中定义一个静态常量 PI。
在类中定义静态的属性(成员变量),在 main() 方法中可以直接访问,也可以通过类名访问,还可以通过类的实例对象来访问。
注意:静态变量是被多个实例所共享的。
与成员变量类似,成员方法也可以分为以下两种:
1. 静态方法(或称为类方法),指被 static 修饰的成员方法。
2. 实例方法,指没有被 static 修饰的成员方法。
静态方法与实例方法的区别如下:
静态方法不需要通过它所属的类的任何实例就可以被调用,因此在静态方法中不能使用 this 关键字,也不能直接访问所属类的实例变量和实例方法,但是可以直接访问所属类的静态变量和静态方法。另外,和 this 关键字一样,super 关键字也与类的特定实例相关,所以在静态方法中也不能使用 super 关键字。
在实例方法中可以直接访问所属类的静态变量、静态方法、实例变量和实例方法。
在访问非静态方法时,需要通过实例对象来访问,而在访问静态方法时,可以直接访问,也可以通过类名来访问,还可以通过实例化对象来访问。
静态代码块指 Java 类中的 static{ } 代码块,主要用于初始化类,为类的静态变量赋初始值,提升程序性能。
静态代码块的特点如下:
静态代码块类似于一个方法,但它不可以存在于任何方法体中。
静态代码块可以置于类中的任何地方,类中可以有多个静态初始化块。
Java 虚拟机在加载类时执行静态代码块,所以很多时候会将一些只需要进行一次的初始化操作都放在 static 代码块中进行。
如果类中包含多个静态代码块,则 Java 虚拟机将按它们在类中出现的顺序依次执行它们,每个静态代码块只会被执行一次。
静态代码块与静态方法一样,不能直接访问类的实例变量和实例方法,而需要通过类的实例对象来访问。
在 JDK 1.5 之后增加了一种静态导入的语法,用于导入指定类的某个静态成员变量、方法或全部的静态成员变量、方法。如果一个类中的方法全部是使用 static 声明的静态方法,则在导入时就可以直接使用 import static 的方式导入。
静态导入使用 import static 语句,静态导入也有两种语法,分别用于导入指定类的单个静态成员变量、方法和全部静态成员变量、方法,其中导入指定类的单个静态成员变量、方法的语法格式如下:
import static package.ClassName.fieldName|methodName;
导入指定类的全部静态成员变量、方法的语法格式如下:
import static package.ClassName.*;
final 在 Java 中的意思是最终,也可以称为完结器,表示对象是最终形态的,不可改变的意思。
使用 final 关键字声明类、变量和方法需要注意以下几点:
* final 用在变量的前面表示变量的值不可以改变,此时该变量可以被称为常量。
* final 用在方法的前面表示方法不可以被重写(子类中如果创建了一个与父类中相同名称、相同返回值类型、相同参数列表的方法,只是方法体中的实现不同,以实现不同于父类的功能,这种方式被称为方法重写,又称为方法覆盖。这里了解即可,教程后面我们会详细讲解)。
* final 用在类的前面表示该类不能有子类,即该类不可以被继承。
1. final 修饰类中的变量
表示该变量一旦被初始化便不可改变,这里不可改变的意思对基本类型变量来说是其值不可变,而对对象引用类型变量来说其引用不可再变。其初始化可以在两个地方:一是其定义处,也就是说在 final 变量定义时直接给其赋值;二是在构造方法中。这两个地方只能选其一,要么在定义时给值,要么在构造方法中给值,不能同时既在定义时赋值,又在构造方法中赋予另外的值。
2. final 修饰类中的方法
说明这种方法提供的功能已经满足当前要求,不需要进行扩展,并且也不允许任何从此类继承的类来重写这种方法,但是继承仍然可以继承这个方法,也就是说可以直接使用。在声明类中,一个 final 方法只被实现一次。
3. final 修饰类
表示该类是无法被任何其他类继承的,意味着此类在一个继承树中是一个叶子类,并且此类的设计已被认为很完美而不需要进行修改或扩展。
对于 final 类中的成员,可以定义其为 final,也可以不是 final。而对于方法,由于所属类为 final 的关系,自然也就成了 final 型。也可以明确地给 final 类中的方法加上一个 final,这显然没有意义。
final 修饰的变量即成为常量,只能赋值一次,但是 final 所修饰局部变量和成员变量有所不同。
* final 修饰的局部变量必须使用之前被赋值一次才能使用。
* final 修饰的成员变量在声明时没有赋值的叫“空白 final 变量”。空白 final 变量必须在构造方法或静态代码块中初始化。
实例:
public class FinalDemo {
void doSomething() {
// 没有在声明的同时赋值
final int e;
// 只能赋值一次
e = 100;
System.out.print(e);
// 声明的同时赋值
final int f = 200;
}
// 实例常量
final int a = 5; // 直接赋值
final int b; // 空白final变量
// 静态常量
final static int c = 12;// 直接赋值
final static int d; // 空白final变量
// 静态代码块
static {
// 初始化静态变量
d = 32;
}
// 构造方法
FinalDemo() {
// 初始化实例变量
b = 3;
// 第二次赋值,会发生编译错误
// b = 4;
}
}
inal 修饰的方法不可被重写,如果出于某些原因,不希望子类重写父类的某个方法,则可以使用 final 修饰该方法。
Java 提供的 Object 类里就有一个 final 方法 getClass(),因为 Java 不希望任何类重写这个方法,所以使用 final 把这个方法密封起来。但对于该类提供的 toString() 和 equals() 方法,都允许子类重写,因此没有使用 final 修饰它们。
public class FinalOverload {
// final 修饰的方法只是不能被重写,完全可以被重载
public final void test(){}
public final void test(String arg){}
}
final 修饰的类不能被继承。当子类继承父类时,将可以访问到父类内部数据,并可通过重写父类方法来改变父类方法的实现细节,这可能导致一些不安全的因素。为了保证某个类不可被继承,则可以使用 final 修饰这个类。
下面代码示范了 final 修饰的类不可被继承。
final class SuperClass {
}
class SubClass extends SuperClass { //编译错误
}
因为 SuperClass 类是一个 final 类,而 SubClass 试图继承 SuperClass 类,这将会引起编译错误。
在 Java 中,main() 方法是 Java 应用程序的入口方法,程序在运行的时候,第一个执行的方法就是 main() 方法。main() 方法和其他的方法有很大的不同。
需注意:
1. 访问控制权限是公有的(public)。
2. main() 方法是静态的。如果要在 main() 方法中调用本类中的其他方法,则该方法也必须是静态的,否则需要先创建本类的实例对象,然后再通过对象调用成员方法。
3. main() 方法没有返回值,只能使用 void。
4. main() 方法具有一个字符串数组参数,用来接收执行 Java 程序的命令行参数。命令行参数作为字符串,按照顺序依次对应字符串数组中的元素。
5. 字符串中数组的名字(代码中的 args)可以任意设置,但是根据习惯,这个字符串数组的名字一般和 Java 规范范例中 main() 参数名保持一致,命名为 args,而方法中的其他内容都是固定不变的。
6. main() 方法定义必须是“public static void main(String[] 字符串数组参数名)”。
7. 一个类只能有一个 main() 方法,这是一个常用于对类进行单元测试(对软件中的最小可测试单元进行检查和验证)的技巧。
声明可变参数的语法格式如下:注意:可变参数必须定义在参数列表的最后。
methodName({paramList},paramType…paramName)
实例:
每次参加考试的人数是不固定的,但是每次考试完之后都需要打印出本次考试的总人数以及参加考试的学生名单。下面编写程序,使用方法的可变参数实现该功能,具体的代码如下:
public class StudentTestMethod {
// 定义输出考试学生的人数及姓名的方法
public void print(String...names) {
int count = names.length; // 获取总个数
System.out.println("本次参加考试的有"+count+"人,名单如下:");
for(int i = 0;i < names.length;i++) {
System.out.println(names[i]);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
StudentTestMethod student = new StudentTestMethod();
student.print("张强","李成","王勇"); // 传入3个值
student.print("马丽","陈玲");
}
}
在 Student TestMethod 类中定义了 print() 方法和 main() 方法。print() 方法声明了一个 String 类型的可变参数,方法体打印可变参数的总个数以及参数值。在 main() 方法中创建了 StudentTestMethod 类的实例,然后分别传入不同个数的参数调用 print() 方法。
构造方法是类的一种特殊方法,用来初始化类的一个新的对象,在创建对象(new 运算符)之后自动调用。Java 中的每个类都有一个默认的构造方法,并且可以有一个以上的构造方法。
Java 构造方法有以下特点:
* 方法名必须与类名相同
* 可以有 0 个、1 个或多个参数
* 没有任何返回值,包括 void
* 默认返回类型就是对象类型本身
* 只能与 new 运算符结合使用
注意:构造方法不能被 static、final、synchronized、abstract 和 native(类似于 abstract)修饰。构造方法用于初始化一个新对象,所以用 static 修饰没有意义。构造方法不能被子类继承,所以用 final 和 abstract 修饰没有意义。多个线程不会同时创建内存地址相同的同一个对象,所以用 synchronized 修饰没有必要。
构造方法的语法格式如下:在一个类中,与类名相同的方法就是构造方法。每个类可以具有多个构造方法,但要求它们各自包含不同的方法参数。
class class_name {
public class_name(){} // 默认无参构造方法
public ciass_name([paramList]){} // 定义构造方法
…
// 类主体
}
实例:
public class MyClass {
private int m; // 定义私有变量
MyClass() {
// 定义无参的构造方法
m = 0;
}
MyClass(int m) {
// 定义有参的构造方法
this.m = m;
}
}
析构方法与构造方法相反,当对象脱离其作用域时(例如对象所在的方法已调用完毕),系统自动执行析构方法。析构方法往往用来做清理垃圾碎片的工作,例如在建立对象时用 new 开辟了一片内存空间,应退出前在析构方法中将其释放。
在 Java 的 Object 类中还提供了一个 protected 类型的 finalize() 方法,因此任何 Java 类都可以覆盖这个方法,在这个方法中进行释放对象所占有的相关资源的操作。
对象的 finalize() 方法具有如下特点:
垃圾回收器是否会执行该方法以及何时执行该方法,都是不确定的。
finalize() 方法有可能使用对象复活,使对象恢复到可触及状态。
垃圾回收器在执行 finalize() 方法时,如果出现异常,垃圾回收器不会报告异常,程序继续正常运行。
例如:
protected void finalize() {
// 对象的清理工作
}
Java 中使用 package 语句定义包,package 语句应该放在源文件的第一行,在每个源文件中只能有一个包定义语句,并且 package 语句适用于所有类型(类、接口、枚举和注释)的文件。定义包语法格式如下:
package 包名;
包(package)的原则:
a. 包类似于文件夹,文件放在文件夹中,类和接口则放在包中。为了便于组织,文件夹一般是一个有层次的树形结构,包也类似。
b. 包名以逗号 `.` 分隔,表示层次结构。
c. Java 中命名包名的一个惯例是使用域名作为前缀,因为域名是唯一的,一般按照域名的反序来定义包名,比如,域名是:apache.org,包名就以 org.apache 开头。
d. **包名和文件目录结构必须完全匹配**。 Java 解释器运行过程如下:
1. 找出环境变量 CLASSPATH,作为 `.class` 文件的根目录。
2. 从根目录开始,获取包名称,并将逗号 `.` 替换为文件分隔符(反斜杠 `/`),通过这个路径名称去查找 Java 类。
一个类可以使用所属包中所有类,以及其它包中公共类(public class)。
同一个包下的类之间互相引用是不需要包名的,可以直接使用。但如果类不在同一个包内,则必须要知道其所在的包,使用有两种方式:
- 通过类的完全限定名
- 通过 `import` 将用到的类引入到当前类
通过类的完全限定名
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());
}
}
使用-classpath(或-cp,或者java9中的--class-path)选项指定类路径:
java -classpath /home/user/classdir:.:/home/user/archives/archive.jar MyProg
或
Java -classpath c:\classdir;.;c:\archives\archive.jar MyProg
1)创建一个名为 com.dao 的包。
2)向 com.dao 包中添加一个 Student 类,该类包含一个返回 String 类型数组的 GetAll() 方法。Student 类代码如下:
package com.dao;
public class Student {
public static String[] GetAll() {
String[] namelist = {"李潘","邓国良","任玲玲","许月月","欧阳娜","赵晓慧"};
return namelist;
}
}
3)创建 com.test 包,在该包里创建带 main() 方法的 Test 类。
4)在 main() 方法中遍历 Student 类的 GetAll() 方法中的元素内容,在遍历内容之前,使用 import 引入 com.dao 整个包。完整代码如下:
package com.test;
import com.dao.Student;
public class Test {
public static void main(String[] args) {
System.out.println("学生信息如下:");
for(String str:Student.GetAll()) {
System.out.println(str);
}
}
}
每一个应用系统都离不开用户模块。用户模块除了提供登录之外,还允许用户查看自己的信息和进行修改。本实例将创建一个用户类,然后再创建一个测试类调用用户类,实现修改密码的功能。
定义用户名和密码:
public class Member {
// 用户类
private String username; // 用户名
private String password; // 密码
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Member(String username,String password) {
this.username = username;
this.password = password;
}
public String toString() {
// 输出用户信息
return"用户名:"+username+"\n密码:"+password;
}
}
创建 MemberTest 类实现修改密码的功能,即当用户输入的密码与原来密码相同时方可进行修改密码操作,否则提示用户输入的密码不正确。具体的实现代码如下:
import java.util.Scanner;
public class MemberTest {
public static void main(String[] args) {
Member admin = new Member("admin","123456"); // 创建用户对象
Scanner input = new Scanner(System.in);
System.out.println("请输入原密码:");
String pwd = input.next(); // 获取用户输入的原密码
if(pwd.equals(admin.getPassword())) {
// 对用户输入的密码进行验证
System.out.println("请输入新密码:");
admin.setPassword(input.next()); // 获取用户输入的新密码
} else {
System.out.println("输入的密码错误,无法进行修改!");
}
System.out.println("----------------用户信息----------------\n"+admin);
}
}
在 main() 方法中创建了 Member 类的对象 admin,并访问了该对象的成员变量 password 和成员方法 toString()。运行该程序。当用户输入的原密码正确时,则可以继续向控制台输入新的密码,并将输入的新密码赋值给 Member 类的 password 属性,从而输出更新后的用户信息。
每个员工都会有自己的档案,主管可以查看在职员工的档案。使用 Java 创建一个员工实体类,然后通过构造方法创建一个名为“王洁”的员工,最后打印出员工档案信息。示例步骤如下。
(1) 创建 Person 类,在该类中定义个人基本信息属性,并定义一个带有参数的构造方法,代码如下:
public class Person {
private String name; // 姓名
private int age; // 年龄
private String sex; // 性别
private String birthday; // 出生日期
private String constellation; // 星座
public Person(String name,int age,String sex,String birthday,String constellation) {
this.name = name;
this.age = age;
this.sex = sex;
this.birthday = birthday;
this.constellation = constellation;
}
public String intro() {
return"姓名:"+name+"\n年龄:"+age+"\n性别:"+sex+"\n出生日期:"+birthday+"\n星痤:"+constellation;
}
}
在 Person 类中,首先声明了 5 个修饰符为 private 的成员变量(属性),然后定义了 Person 类的构造方法,该构造方法中需要传递 5 个参数,并将传递的这 5 个参数值赋给该类中的 5 个成员变量。接着创建了 intro() 方法,返回个人基本信息内容。
(2) 创建 PersonTest 类,并在该类中创建 main() 方法作为该程序的入口。在 main() 方法中使用 Person 类的构造方法对其属性进行初始化,并调用 intro() 方法,输出个人基本信息。代码如下:
public class PersonTest {
public static void main(String[] args) {
Person person = new Person("王洁",21,"女","2016-02-21","狮子座");
String intro = person.intro();
System.out.println(intro);
}
}
在 TestPerson 类中调用了 Person 类的构造方法,并调用了 intro() 方法,从而完成了打印个人基本信息的功能。