(2021.08.15 Sun)
创建对象
假定一个类的名字为demoClass,则创建该类一个对象的语法如下
demoClass a = new demoClass();
String
类与其他类型不同,可将字面量赋给它,如同基本数据类型一样,而这种赋值方法仅适用于String
类和其他表示基本数据类型的类,如Integer
和Double
。
String a = "adfasdf"
Float b = 12.6F
对象创建过程
使用运算符new
创建对象时,依次发生如下几件事:
- 创建给定类的实例(instance)
- 为实例分配内存
- 调用给定类的构造函数,构造函数用于初始化新对象及其变量,创建该对象所需的其他对象,并执行初始化该对象所需的其他操作
同一个类中可以有多个构造函数,每个构造函数的参数类型和数目不同。使用new
时,可以在参数列表中指定不同的参数,这将调用响应的构造函数。如果类中没有定义构造函数,创建对象时,默认将调用没有参数的构造函数,其作用是调用超类中不接收任何参数的构造函数。
内存管理和引用
与Python相似,Java中的内存管理是动态和自动的,并且不需要使用者特别关心。创建对象时分配内存的任务由Java虚拟机(VM)完成。对象使用完成后,Java能够判断出该对象已经不再有任何活动的引用(即该对象没有被赋给任何正在使用的变量或被存储在数组中)。
动态垃圾回收:Java VM定期检查未用的对象,并收回这些对象占用的内存。
将对象赋给变量或其他作为参数传递给方法时,实际上没有使用对象,只是对对象的引用。对对象的引用实际上是指针。
比较对象时,可比较两个对象的名字是否是(指向)同一个对象(用==
),也可比较两个对象的值是否相同(用String.equals()
)。
class testClass {
public static void main(String[] arguments) {
String a, b, c;
a = 'asdf';
b = a;
c = "asdf";
System.out.println("a and b the same object: " + (a==b)); // true
System.out.println("a and c the same object: " + (a==c)); // false
System.out.println("a and c the same value: " + (a.equals(c))); // true
}
类变量和实例变量
类变量适用于类和所有实例。类变量只有一个copy,修改它的值将改变所有实例。类变量在类中定义时,前面加关键字static
。
class familyMember {
static String surname = "James";
String giverName;
int = age;
}
调用类变量时直接引用类名和类变量名即可
System.out.println(familyMember.surname);
对类变量的修改将影响该类的所有对象。
实例变量可在初始化时赋值,引用实例变量需要指定实例的名字,而非类名。
familyMember a = new familyMember;
a.givenName = "Clarke";
a.age = 38;
System.out.println("age: "+ a.age);
对象和基本数据类型的强制类型转换(casting)
强制转换基本数据类型
一个基本原则是目标类型应该比源类型保存更大的值。譬如,byte
类型范围是-128~127,可强制转换为short
类型,而反过来则不行。由于更大范围的类型比更小范围类型的精确度高,所以不会导致信息丢失。一个例外是整数转换为浮点数,long
float
/double
时,都将导致精度降低。
可能的转换顺序:
byte
/char
int
float
/long
double
转换的格式如下
// (tpename) value
float a = 9.0;
int b = (int) (a); // (int) a;
强制转换对象
必须满足条件:源类和目标类之间存在继承关系,即其中的一个是另一个的子类。子类有着比超类更多的方法和属性。要在需要子类对象的地方使用超类对象,需要进行显式的强制类型转换。在转换过程中,不会损失任何信息,而得到了子类定义的全部方法和变量。
在下面案例中,VicePresident
是Employee
的子类,包含更多信息。
// (classname) object
Employee emp = new Employee();
VicePresident veep = new VicePresident();
emp = veep;
veep = (VicePresident) emp;
对象与类的关系判断
判断一个对象所属的类,或该对象是否属于某个类。
- 方法1:在
Object
类中定义了一个方法getClass
,所有Java对象都包含它,这个方法返回一个Class
对象,指出了对象所属的类,对象的getName
方法返回一个表示类名的字符串。
// define an instance kk
String name = kk.getClass().getName();
- 方法2:
instanceof
运算符,该运算符操作两个部分,左为对象的引用,右为类名,返回一个boolean
值
boolean check 1 = "Shanghai" instanceof String;
基本类型和对象之间的转换
java.lang
包中包含了对应于每种基本数据类型的类:Float
、Boolean
、Byte
等,这些类的大多与数据类型的名称相同,只是类名首字母大写,即Short
而非short
。另外,有两个类的名称与对应的数据类型不同,即char
-Character
和int
-Integer
。
每个基本类型对应的类,可以创建存储相同值的对象。
Integer dataCount = new Integer(11);
int newCount = dataCount.intValue();
将字符串转换成数字类型比如int
时,可用Integer
的内置方法parseInt()
。
String penn = '65535';
int pen = Integer.parseInt(penn);
通过自动封装(autoboxing)和拆封(unboxing),这两个自动转换过程,处理表示同一类值的基本类型和对象时更为容易。
Float f1 = 12.5F;
Float f2 = 27.2F;
System.out.println('lower number: " + Math.min(f1, f2));
这里的f1
和f2
都是对象,而Math.min
方法接收float
参数却被传递了对象。编译器将Float
对象拆封为float
值,再将其传递给Math.min
方法。
对字符串的分割
对字符串的分割使用java.util
中的StringTokenizer
类。
import java.util.StringTokenizer
class TokenTest {
public static void main(String[] arguments) {
String a = "asdf 33242 3.4";
String b = "asdf@fadf@123";
StringTokenizer t1, t2;
t1 = new StringTokenizer(a);
System.out.println("part 1: "+t1.nextToken());
System.out.println("part 2: "+t1.nextToken());
System.out.println("part 1: "+t1.nextToken());
t2 = new StringTokenizer(b, '@');
System.out.println("part 1: "+t2.nextToken());
System.out.println("part 2: "+t2.nextToken());
System.out.println("part 1: "+t2.nextToken());
}
}
Reference
1 R. Cadenhead著,袁国忠译,21天学通Java(第7版),中国工信出版集团,人民邮电出版社