板凳----On_Java 第三章对象无处不在

3.1通过引用操作对象

所有编程语言都在内存中处理各种元素。“将一切都视为对象”, 但你实际操作的其实是该对象的引用( reference)。
所以一种安全的做法是 始终在创建引用时就进行初始化
String s = “abcdf”;

3.2 必须创建所有对象

new String(“asdf”);

3.2.1数据保存在哪里

大多数微处理器芯片有额外的缓存内存,只不过缓存内存使用的是传统的内存管理方式. 而非寄存器, 字符串 String)可以用带引号的文本逬行初始化。而对于其他类型的对象而言 你需要使用一种更为通用的初始化方式。引用的作用是关联对象。通常我们使用new关键字来创建对象。new关键字表达的意思是“我要一个这种类型的对象”。

  1. 寄存器 register)。这是速度最快的数据存储方式 因为它保存数据的位置不同于其他方式 数据会直接保存在中央处理器 central processing unit, CPU ) 然而寄存器的数量是有限的 所以只能按需分配。此外 你不能直接控制寄存器的分配 甚至你在程序中都找不到寄存器存在过的证据( C C++是例外 它们允许你向编译器申请分配寄存器)。
  2. stack)。数据存储在随机存取存储器 random-access memory, RAM 处理器可以通过栈指针 stack pointer 直接操作该数据。具体来说 栈指针向下移动将申请一块新的内存 向上移动则会释放这块内存。这是一种极其迅速和高效的内存分配方其效率仅次于寄存器。只不过Java系统在创建应用程序时就必须明确栈上所有对象的生命周期。这种限制约束了程序的灵活性 因此虽然有一些数据会保存在栈上 尤其是对象引用 对象本身却并非如此。
  3. ( heap )。 这是一个通用的内存池(使用的也是RAM空间) 用于存放所有Java对象。与栈不同的是 编译器并不关心位于堆上的对象需要存在多久。因此 堆的使用是非常灵活的。比如. 当你需要一个対象时 可以随时使用new来创建这个对象 那么当这段代码被执行时, Java会在堆上为该对象分配内存空间。然而这种灵活性是有代价的分配和清理堆存储要比栈存储花费更多的时间(如果你可以像C++那样在栈上创建对象的话) 。
  4. 量存储(constant storage) 。常量通常会直接保存在程序代码中 因为它们的值不会改变 所以这样做是安全的。有时候常量会与其他代码隔离幵来 于是在某些嵌入系统里 这些常量就可以保存在只读存储器(read-only memory, ROM ) 。
  5. RAM存储( non-RAM storage )。如果一段数据没有保存在应用程序里 那么该数据的生命周期既不依赖于应用程序是否运行 也不受应用程序的管制。其中最典型的例子之一是“序列化対象( serialized object),它指的是转换为字节流(叫作“序列化”) 并可以发送至其他机器的对象。另一个例子则是“持久化对象” (persistent object), 它指的是保存在磁盘上的对象 而这些对象即便在程序结束运行之后也依然能够保持其状态。这些数据存储类型的特点在于 它们会将对象转换成其他形式以保存于其他媒介。 然后在需要的时候更新转换回常规的RAM对象。Java支持轻量级的持久化对象存储JDBC以及Hibernate等库则提供了更为成熟的解决方案,即支持使用数据库存取对象信息。

3.2.2特殊情况 基本类型

“基本类型”(primitive type)。它们之所以享受特别待遇 是因为new关键字是在堆上创建对象 这就意味着哪怕 

是创建一些简单的变量也不会很高效。对于基本类型 Java使用了与C以及C++相同的实现机制 这意味着我们无须使用new来创建基本类型的变星 而是直接创建一个“ 自动变量"( automatic variable),注意不是引用。也就是说 该变量会直接在栈上保存它的值,因此运行效率也较高。
Java还为基本类型提供了对应的“包装类 ”( wrapper class),通过包装类可以将基本类型呈现为位于堆上的非原始对象。例如:
char c = ‘x’;
Character ch = new Character©;
也可以这样表示:
Character ch = new Character(‘x’);
Character ch “ 动装箱” ( autoboxing ) 机制能够将基本类型对象自动转换为包装类对象,
例如:
Character ch = ‘x’;
也可以再转换回来 例如:
char c = ch ;

高精度数字
Java提供了两个支持高精度计算的类 分别是Biginteger BigDecimal。虽然这两个类也大致可以被归为包装类 但是它们其实并没有对应的基本类型。 区別只是你用方法代替了运算符而已。此外 由于涉及更多的计算量 导致的结果就是相关操作的效率有所降低。所谓“ 速度换精度”即是如此。
Biginteger可以支持任意精度的整数。也就是说 在运算时你可以表7K任意精度的整数值,而不用担心丢失精度。
BigDecimal可用于任意精度的定点数 fixed-point number )。例如 你可以将其用于货币计算。
3.2.3 Java中的数组
在C C++ 因为数组的本质是内存块 所以使 数组是十分危险的。也就是说. 如果C++程序访问了数组边界之外的内存 或者在内存被初始化之前就对其逬行操作 这个问题非常普遍 那么结果如何就难以预料了。
Java的一个核心设计目的是安全 。例如 Java的数组一定会被初始化 并且无法访问数组边界之外的元素。这种边界检查的代价是需要消耗少许内存 以及运行时需要少量时间来验证索引的正确性。 其背后的假设是 安全性以及生产力的改善完全可以抵消这些代价 同时Java也会优化这些操作 。
当你创建一个用于放置对象的数组时 实际上数组里包含的是引用 而这些引用会被自动初始化为一个特殊的值 null。Java会认为一个值为null的引用没有指向任何对象所以当你操作引用之前 需要确保将其指向了某个对象。如果你试图操作一个值为null引用 系统会返回一个运行时报错。因此 Java通过以上手段规避了那些常见的数组问题。
也可以创建一个放置基本类型的数组。编译器会确保对该数据进行初始化,并将数组元素的值设置为0。

3.3注释

Java支持两种类型的注释。第一种注释是传统的C编程风格 即以/*幵始 中间可以有多行的注释内容 然后以•/ 结束。
第二种注释源于C++。这种注释以〃幵始 到同一行的末尾结束 因此是一种单行注释。因为这种注释简单易用 所以使用频率很高。

3.4 无须销毁对象

将展示Java如何帮你释放内存并大幅简化这些问题。
3.4.1 作用域
作用域会决定其范围内定义的变量名的可见性和生命周期。C、C++以及Java的作用域范围都是通过大括号 {})定义的
3.4.2对象的作用域
Java对象的生命周期和基本类型有所不同。当你使用new创建一个对象时 该对象在作用域结束后会依然存在。
通过new创建的対象会存在足够长的时间 因此C++编程中出现的一系列问题在Java中就消失了。在编写C++代码时 你不仅要确保对象在需要的时候随时可用, 而且事后还要负责销毁这些对象。

为什么应用程序并没有因为内存溢出而强行结束呢 而这一点也正是C++存在的问题。
原因就在于 Java使用了一点魔法:即垃圾收集器会监视所有通过new创建的对象, 并及时发现哪些对象不再被引用
然后它会释放这些对象所占用的内存。 使得这些内存可以用于其他新对象。这意味着你无须关注何时需要释放内存 你要做的只是创建对象而已 如果你不再需要这些对象 就任由它们去吧(垃圾收集器会处理它们) 。这种机制解决了一类非常严重的编程问题 由于程序员忘记释放内存而导致的“内存泄漏" ( memory leak ) 。

3.5 使用class关键字创建新类型

面向对象编程语言会使用“class”关键字来描述新的对象种类。其用法是class关键字后面跟着新的类名
class ATypeName {
//类的具体实现放在这里
}
是可以通过new关键字创建一个该类的对象
ATypeName a = new ATypeName();
字段
当定义一个类时 你可以为其定义两种元素 字段 有时叫作“数据成员” 和方法有时叫作“成员函数” 。我们通过对象的引用与字段进行交互。字段可以是任何类型的对象 也可以是基本类型。如果一个字段是某个对象的引 . 你必须通过new关键字参考之前的相关介绍 初始化该引用并将其关联到具体的对象上。
这段代码创建了一个新的类 只不过其内容只包含了一行注释 因此目前也没有什么实际的作用。话虽如此 你还是可以通过new关键字创建一个该类的对象每一个对象都会单独保存其字段。通常来说 不同对象的字段之间不会共享。
通过对象成员为字段赋值。具体做法是 先写出对象的引用名 跟着再写一个“•”,然后是对象的成员名
class DataOnly {
int i;
double d;
boolean b;
}
class ATypeName {
//类的具体实现放在这

可以这样为字段赋值:
data.i = 47;
data.d = 1.1;
data.b = false;

基本类型的默认值
当一个类的字段是基本类型时 即便你没有初始化这些字段 它们也会拥有默认值
在这里插入图片描述

当变量作为类成员存在时 Java才会将其初始化为以上的默认值。
这种机制并不会应用于局部变量 local variable ,因为局部变量并不是类的字段。

class A {   
	public int i;

	public A(){

	}
	public A(int j){
		i = j;
	}

	public void show(){
		System.out.println("%d\n" + i);
	}
}

class TestConst_1{
	public static void main(String[] args){
		A aa = new A();
		aa.show();
   	//	int k;
//   System.out.println(“%d\n” + k);

	}
}

(base) wannian07@wannian07-PC:~/Desktop/java/code$ java TestConst_1
%d
0
(base) wannian07@wannian07-PC:~/Desktop/java/code$ javac TestConst_1.java
TestConst_1.java:22: 错误: 可能尚未初始化变量k
System.out.println(“%d\n” + k);
^
1 个错误

3.6 方法、参数以及返回值

https://blog.csdn.net/qq_39236499/article/details/119613296
许多编程语言(比如C C++ ) “函数 function ) 用于表示子程序。而在Java , 我们称之为“方法”( method ),意思是“做某件事的方式”。
Java中的方法决定了对象可以接受哪些消息。方法最基础的几个部分包括 方法名、参数、 回值. 以及方法体( method body ) 。
ReturnType表示当调用一个方法时 该方法生成的值是什么类型。参数列表提供了一 系列需要传递给方法的信息. 包括信息的类型和名称。方法名和参数列表共同构成了方法的“签名”( signature ),方法签名即该方法的唯一标识符。
调用对象方法的具体方式为 在对象引用之后添加一个“•”,然后紧跟着方法名及其参数列表

int x = a.f();
需要注意的是 返回值的类型必须与变量x的类型保持一致。这种调用方法的行为也被描述为“向一个对象发送一条消息”。 f()代表消息 , a代表对象。此外,我们也可以将面向对象编程描述为“向对象发送消息”。
参数列表
参数列表描述了需要传递方法的信息。需要描述这些对象的类型以及对象名。当操作对象时,实际操作的是它的引用。
Java程序似乎就是一群对象将其他对象设置为其方法的参数 然后向这些对象发送消息。
int storage(String s){
return s.length() * 2;
}
传递对象实际上就是传递对象的引用
return : 1. 告诉“从方法中离开, 一切都结束了”
2、当该方法生成了一个值的时候, 将这个值放在return 之后。

class A{
	public int i;
	
	public A(int j){
		i = j;
	}
	public void show(){
		System.out.println("i = " + i);
	}
}

class TestConst_2{
	public static void main(String[] args){
		A aa1 = new A(5);
		A aa2 = new A(8);
		aa1.show();
		aa2.show();
	}
}

(base) wannian07@wannian07-PC:~/Desktop/java/code$ java TestConst_2
i = 5
i = 8
aa1和aa2 在内存中分别有各自的数据成员i, 实际上每个非static方法中都隐含这个this指针。指向当前正在调用该方法的对象。

class A{
	private int i;
	
	public A(int i){
//将形参i赋给该构造方法,本次运行所创建的那个新对象的i 数据成员
		this.i = i;
	}
	public void show(){
//this表示当前时刻正在调用show()方法的对象, this可以省略
		System.out.println("i = " + this.i);
	}
}

class TestConst_3{
	public static void main(String[] args){
		A aa1 = new A(100);
		A aa2 = new A(888);
		aa1.show();
		aa2.show();
	}
}

(base) wannian07@wannian07-PC:~/Desktop/java/code$ java TestConst_3
i = 100
i = 888

3.7编写Java程序

static 关键字
创建一个类即描述了其对象的外观和行为。直到使用new关键字时 你才会真正创建一个对象 以及为该对象分配内存 并使得其方法可以被调用。
例外: 第一种情况是 有时候我们需要一小块共享空间来保存某个特定的字段.而并不关心创建多少个对象 甚至有没有创建对象。

class A{
	//public int i = 10;
	public static int  i = 10;
	public void show(){
		System.out.println("%d\n" +  i);
	}
}

class TestStatic_1{
	public static void main(String[] args){
		A aa1 = new A();
		A aa2 = new A();
		A aa3 = new A();

		aa1.i = 20;
		aa2.show();

		System.out.println("%d\n" +  aa3.i);	
	}
}

//(base) wannian07@wannian07-PC:~/Desktop/java/code$ java TestStatic_1
//%d
//10

(base) wannian07@wannian07-PC:~/Desktop/java/code$ java TestStatic_1
%d
20
%d
20

第二种情况是 你需要使用一个类的某个方法,而该方法和具体的对象无关 换句话说,你希望即便没有生成任何该类的对象 依然可以调用其方法。

class A{
//static 属于i是属于类本身
// 没有对象, 仍然可以直接通过类名方式访问该类内部的static属性
//static 方法show()同理
	public static int i = 10;
	
	public static void show(){
		System.out.println("Hello World!");
	}
}

class TestStatic_2{
	public static void main(String[] args){
		
		System.out.println("%d\n" +  A.i);	
		A.show();
	}
}

(base) wannian07@wannian07-PC:~/Desktop/java/code$ java TestStatic_2
%d
10
Hello World!

class A{
//static 属性和方法虽然属于类本身, 虽然可以通过类名的方式访问,
//但是static属性和方法很明显也属于类对象,当然也可以通过类的对象名的方式访问
	public static int i = 10;
	
	public static void show(){
		System.out.println("Hello World!");
	}
}

class TestStatic_3{
	public static void main(String[] args){
		A aa = new A();
			
		aa.show();
		System.out.println("%d\n" +  aa.i);
	}
}

(base) wannian07@wannian07-PC:~/Desktop/java/code$ java TestStatic_3
Hello World!
%d
10

class A{
//只有非private的static成员才可以通过类名的方式访问
//static只是表明该成员具有了可以通过类名访问的潜在的特征,前提必须是非private
	protected  static int i = 10;
	
//	private static void show(){
//		System.out.println("Hello World!");
//	}
}

class TestStatic_4{
	public static void main(String[] args){
//A.show();
System.out.println("%d\n" +  A.i);
	}
}

(base) wannian07@wannian07-PC:~/Desktop/java/code$ javac TestStatic_4.java
TestStatic_4.java:12: 错误: show() 在 A 中是 private 访问控制
A.show();
^
(base) wannian07@wannian07-PC:~/Desktop/java/code$ java TestStatic_4
%d
10

class A{
	protected static int i = 10;
	
	public static void show(){
		// g()    //error static方法不能访问非static 方法
		System.out.println("Hello World!");
	}

	public void g(){
		show();
		System.out.println("I loved Java!");
	}
}

class TestStatic_5{
	public static void main(String[] args){
		//A.show();
		//A.g();
		A aa = new A();
		aa.g();	//非static方法可以访问static成员
		//aa.show();
		System.out.println("%d\n" +  A.i);
	}
}
  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值