第二章 一切都是对象

2.1 用引用操纵对象

Java一切都视为对象,使用标识符来操作对象,标识符实际是对象的一个引用。
例如:采用遥控器来控制电视机
创建一个引用,不一定需要有一个对象与之关联。

String s;
//此时拥有一个引用,但是却没有一个对象与之关联。
//但是此时向引用s返送消息,这是会返回一个错误,此时没有一个对象与之关联。

创建一个引用的使用同时进行初始化

String s = "asdf";

2.2 必须有你来创建所有对象

一旦创建了一个引用,就希望有一个对象与之关联。
❓那么如何创建一个对象呢?
通常使用new操作符。new:给我一个新的对象

String s = new String("asdf");
//不仅创建了一个新的字符串,而且进行了初始化

2.2.1 存储到什么地方

  1. 寄存器
  2. 堆栈
    堆栈必须知道里面所有项的确切的生命周期,以便上下移动指针,分配或者回收空间。
    这限制了程序的灵活性。
    对象的引用存放在堆栈中

  3. 堆用于存放所有的java对象,编译器不需要知道数据在堆里面具体的存活时间。
  4. 常量存储
  5. 非RAM存储

2.2.2 特例,基本类型

通过上述知道创建对象通过关键字new 来进行创建,对象存放在堆里面,引用存放在堆栈里面。
❓但是程序设计中通常使用到一系列类型,需要特殊对待,基本类型。通过new创建一个对象,特别是小的,简单的 变量,不是很有效。
解决方法 :不用newl来创建变量,而是创建一个变量,这个变量直接存储值,并且置于堆栈 中。
Java中每种基本类型所占据的空间大小

基本类型大小最小值最大值包装器类型
booleanBoolean
char16 bits(2 Byte)02^16-1Charcater
byte8 bits(1 Byte)-2^7(-128)2^7-1(127)Byte
short16 bits(2 Byte)-2^152^15-1Short
int32 bits(4 Byte)-2^312*31-1Integer
long64bits(8 Byte)-2^632^63-1Long
float32bits(4 Byte)Float
double64bits(8 Byte)Double

基本类型是直接创建一个存储值的变量,所以没有对象,但是Java是一个面向对象的程序语言。所以由包装器类,使得可以在堆里面创建一个不是基本类型的对象,用来表示对象的基本类型。

char c = 'x';
//创建一个直接存储x字符的变量c,此时是直接在堆栈里
Character ch = new Character(c);
//创建一个对象,使用字符变量c来进行初始化,对象存放在堆里面。

Character ch = new Character('x');

Java的自动包装功能能够自动的将基本类型和包装器类型进行相互转换

Character ch = 'x';
//将char类型转化成Character
char c = ch;
//将Character转换成char
高精度数字

BigInteger和BigDecimal,可以算是包装器,但是没有对应的基本类型。
没有基本类型的运算符来实现。采用方法来计算采用了时间换取精度的方法

Java中的数组

数组中常出现的错误:

  1. 访问数组之外的数据
  2. 数组没有进行初始化

Java会确保数组进行初始化,并且不会超出数组的范围。
初始化:创建一个数组对象,实际上是创建一个引用数组,每个引用都会自动的被初始化一个特定值,null
null代表引用还没有指定任何一个对象

2.3 永远不需要销毁对象

在程序中变量需要存活多长时间,销毁对象,那么是在什么时候进行的。

2.3.1 作用域(变量)

作用域决定了在其内定义变量的可见性生命周期.

{
	int x = 12;
	{
		int q = 96;
		//q超出了这个范围之后,就不可以访问到了
	}
}

在作用域里面定义的变量只可以用于作用域结束之前。
在Java中不可以进行重复定义变量

{
	int x =12;
	{
		int x =56;
	}
}
//这在c和c++里是被允许的,用较小的作用域来覆盖较大的作用域。在Java里面不被允许

2.3.2 对象的作用域

Java对象和基本类型的生命周期是不一样的。
当用new来创建一个对象的时候,可以存活于作用域之外。

{
 String s = new String ("asdf");
 }

引用s在作用域结束之后就访问不到了。但是s指向的对象仍然占据着空间。
超出了作用域之后在访问这个对象,因为他的唯一引用已经超出了范围。
new创建的对象,会一直保留。
Java里面有一个垃圾回收器,用来监视new创建的所有对象,并辨别不会再被引用的对象,释放内存空间。

2.4 创建新的数据类型: 类

通过引用可以指向一个对象
通过new可以创建一个对象
❓那么对象是由什么决定的呢
决定了对象的外观和行为。
通过class关键字来创建一个类
class:我告诉你一种新类型的对象的样子

class ATypeName{
	/*
	class body
	*/
}

现在已经创建了一种新的类型,可以通过new关键字来创建这种类型的对象了。

ATypeName a = new ATypeName();

此时还没有定义类的方法,还没有办法让这个类做更多的事情。

2.4.1字段和方法

定义一个类(编写Java程序的主要工作是定义一个类,产生类的对象,发送消息给对象),就可以让类做更多的事情。通过定义字段方法
字段:可以是任何类型的对象,通过引用和其通信。也可以是基本类型。

class DataOnly{
	int i;
	double d;
	boolean b;
}

现在这个类还什么都不可做,除了存储数据,但是可以创建他的一个对象,给里面的字段进行赋值。

DataOnly data = new DataOnly();

引用对象的成员:在对象引用的后面紧接着一个句点,然后是对象内部的成员名称。
objectReference.member

data.i = 47;
data.d = 1.1;
data.b = false;

对象中也可以包含是对象类型的字段

//对象的引用myPlane
//对象里面的对象字段的引用名leftTank
//对象lefttank类型的字段是capacity
myPlane.leftTank.capacity = 100;

此时DataOnly除了保存数据之外没有别的用处,没有任何成员方法。
了解成员方法之前,先了解参数返回值

基本成员默认值

的某个成员是基本类型,即使没有初始化,那么java也会确保他有一个默认值

基本类型默认值
booleanfalse
char
byte0
short0
int0
long0
float0.0
double0.0

⚠只有变量作为的成员的时候才会有默认值,作为类的方法的变量的时候不会有默认值(不适用于局部变量)

2.5 方法、参数和返回值

Java的方法决定了一个对象能够接受什么样的消息。
方法的组成部分:名称、参数、返回值、方法体。

ReturnType methodName(Argument list){
	method body
}

返回值:方法执行之后返回的值
参数列表:方法接受信息的类型和名称
**方法名和参数列表(方法签名)**能够唯一的标识一个方法
Java中的方法只能作为类的一部分进行创建。所有方法只能通过对象来调用(静态方法除外),并且这个对象能够调用这个方法。当调用不存在的方法的时候,会报错。
objectName.methodName(arg1, arg2, arg3)
可以通过一个变量来接受方法的返回值

int f(){
	return 1;
}
int x = a.f();
//接受变量的类型必须和返回值的类型兼容

2.5.1 参数列表

方法的参数列表指定了要传递给方法什么样的消息,这些消息采用的是对象形式。参数列表中指定每个所传递对象的类型和名称。这里面传递的实际也是引用

int storage(String s){
 return s.length()*2;
}

reutrn 关键字的用法:
1.代表方法已经完成,离开此方法。
2.方法返回一个值。
如果不想返回一个值,可以使用void

boolean flag(){return true;}
double naturalLogBase()(return 2.718)
void nothing(){return;}
void nothing2(){}

2.6 构建第一个Java程序

2.6.1 名字的可见性

❓在程序的某个模块使用了一个名字,在另一个模块里面也使用了相同的名字,那么怎么样才能区分这两个名字并且防止冲突呢?
解决方法:给一个类库生成一个不会与其他名字混淆的名字,使用反转的域名。MindView.net反转之后 net.mindview.utility.foibles.
这样就保证了每一个文件都存活于自己的名字空间内,而且都一个文件内的每一个类都有唯一的标识符

2.6.2 运用其他构件

如果想在自己的程序内使用已经定义好的类,那么编译器就必须知道如何定位他。
1.如果这个类可能就在发出调用的那个源文件中,就可以直接使用这个类,即使这个类在这个文件的后面才会被定义。
2. 如果这个类位于其他文件中,如果你想使用某个特定名字的类,但是这个名字的类不止一份。或者是你想添加一个新的类,但是和程序里已有的类相冲突。
所以你必须告诉编译器你想要的那一个类究竟是什么。通过使用import关键字可以解决这个问题。
通过import倒入一个包(类库)
通过使用编译器自带的构件,就不需要写反转的域名

import java.util.ArrayList;
//导入ArrayList这个类
import java.util.*;
//导入util这个类库里面的所有类

2.6.3 static关键字

当创建一个类时,就是在描述这个类的外观和行为。通过new关键字来创建对象,这时候就会为对象分配空间,方法才能会被调用。
两种情况:

  1. 只想为特定域分配单一的存储空间,不考虑创建了多少个对象,甚至不创建对象(针对字段)
  2. 希望某个方法不与包含它的类的任何对象关联一起。不创建对象,就可以使用方法(针对方法)

通过static关键字可以解决上述两个问题。
用static修饰的字段和方法可以代表为类数据类方法

class StaticTest{
	static int i = 47;
}

static修饰的字段,无论创建了多少个对象都只有一个存储空间,所有的对象都共享同一个字段

StaticTest st1 = new StaticTest();
StaticTest st2 = new StaticTest();
st1.i 和 st2.i都指向同一个位置

使用static修饰字段有两个方法
3. 通过创建对象
4. 直接通过使用类名直接引用

StaticTest.i++;

建议使用类名来引用static变量,不仅强调了是static共享的数据,而且提供了优化。

静态方法

class Incrementable{
	static void increment(){
	StaticTest.i++;
	}
}

调用

Incrementalbe sf = new Incrementable();
sf.increment()
//或者
Incrementable.increment();

static修饰的main方法就是在不创建任何对象的情况下就可以调用它,这个方法是程序的入口。

2.7 你的第一个Java程序

 //HelloData.java
//打印当前日期的字符串
import java.util.Date;
//这里需要打印当前日期,我们使用编译器自带的构建,同时通过import关键字告诉编译器我们要使用的那个类的位置
//这是创建一个类,限制了对象的外观和行为
//类名必须和文件名相同
public class HelloDate{
	//这是一个static类型的方法,可以不通过创建对象就可以直接使用
	//方法的返回值类型是void,
	//方法名称是main,方法的参数列表是一个String类型的数组,实际是数组的一个引用
	public static void main(String args[]){
		//System大写代表这是一个类名,通过类名调用一个对象,说明这个方法是静态字段
		//直接有一个out对象,然后调用println()方法
		System.out.println("Hello, It's");
		System.out.println(new Date());
		// return;
	}
}

编译和运行

编译:javac 类名.java
运行:java 类名

2.8 注释和嵌入式文档

第一种注释

/* 
*	This is a comment
*	that continues
*	across lines
*/

第二种注释

// This is a one-line comment

2.8.1 注释文档

对代码文档的维护。将代码和文档连接起来,放在同一个文件里。同时还必须使用特殊的注释语法来标记文档,同时使用javadoc来提取注释。

2.8.2 语法

2.9代码风格

为了保持开发程序的一致性,代码风格规定

  1. 类名的首字母大写,多个单词并在一起,并且每一个都是大写
class AllTheColorsOfTheRainbow{}
  1. 方法、字段以及对象的引用第一个字母都是小写
class AllTheColorOfTheRainbow{
	int anIntegerRepresentingColors;
	void changeTheHueOfTheColor(int newHue){
	}
}

2.11 练习

练习1:创建一个类,它包含一个int域和一个char域,他们都没有初始化,将他们的值打印出来,已验证Java执行了默认初始化

如果使用静态访问非静态的话,会出现报错。因为静态会先于类加载。当静态数据将在好的时候,此时类的数据还没有加载,静态里面的非静态会没有加载。

public class Demo{
	//Demo.java:7: 错误: 无法从静态上下文中引用非静态 变量 i
    //System.out.println(i);                 ^
	//Demo.java:8: 错误: 无法从静态上下文中引用非静态 变量 c
    //System.out.println(c);
	
	//这是类的变量
	static int i;
	static char c;
	//这是类的方法
	public static void main(String args[]){
		System.out.println(i);
		System.out.println(c);
	}
}
输出结果:0 
		null(不显示)

练习二:编写HelloDate.java的例子,创建一个Hello,World程序。输出这句话

// HelloWorld.java
public class HelloWorld{
	public static void main(String args[]){
		System.out.println("Hello,World");
	}
}

练习三:找出含有ATypeName的代码段,将其改写成完整的程序

//ATypeName.java
public class ATypeName{
	public static void main(String args[]){
		ATypeName a = new ATypeName();
	}
}

练习四:将DataOnly程序改写成一个程序

//DataOnly.java
public class DataOnly{
	static int i;
	static char c; 
	static boolean f;
	public static void main(String args[]){
		DataOnly data = new DataOnly();
		data.i = 47;
		data.c = 'x';
		data.f = false;
		System.out.println(data.i);
		System.out.println(data.c);
		System.out.println(data.f);
	}
	
}

练习五:编写一个程序,让他含有本章定义的storage方法

//Demo.java
public class Demo{
	public static void main(String args[]){
		int i = storage("sdf");
		System.out.println(i);
	}
	public static int storage(String s){
		return s.length() * 2;
		
	}
}

练习七:将Incrementable的代码改写成一个程序

//Incrementable.java
public class Incrementable{
	static int i = 47;
	public static void add(){
		Incrementable.i++;
	}
	public static void main(String args[]){
		Incrementable.add();
		Incrementable i1 = new Incrementable();
		System.out.println(i1.i);
		Incrementable i2 = new Incrementable();
		System.out.println(i2.i);
	}
}

练习八:展示static域无论有多少个对象,只有一个实例

//Demo.java
public class Demo{
	public static void main(String args[]){
		Demo.c = 'x';
		Demo d1 = new Demo();
		Demo d2 = new Demo();
		System.out.println(d1.c);
		System.out.println(d2.c);
	}
	static char c;
}

练习九:展示自动包装功能对所有的基本类型和包装器类型都起作用

//Demo.java
public class Demo{
	public static void main(String args[]){
		//boolean
		Boolean b = false;
		System.out.println(b);
		boolean b1 = b;
		System.out.println(b1);
		
		//byte 
		Byte bb = 1;
		System.out.println(bb);
		byte bb1 = bb;
		System.out.println(bb1);
		
		//short
		Short s = 2;
		System.out.println(s);
		short s1 = s;
		System.out.println(s1);
		
		//int 
		Integer i = 3;
		System.out.println(i);
		int i1 = i;
		System.out.println(i1);
		
		//long
		//Demo.java:29: 错误: 不兼容的类型: int无法转换为Long
                //Long l = 4;
		//包装器类型不可以从小范围转换到大范围
		//基本类型可以
		Long l = 4L;
		System.out.println(l);
		long l1 = l;
		System.out.println(l1);
		
		//float 
		Float f = 1.0f;
		System.out.println(f);
		float f1 = f;
		System.out.println(f1);
		
		//double
		Double d = 2.9;
		System.out.println(d);
		double d1 = d;
		System.out.println(d1);
		
		//char
		Character c = 'c';
		System.out.println(c);
		char c1 = c;
		System.out.println(c1);
	}
}

练习10: 打印从命令行获得的三个参数

//Demo.java
public class Demo{
	public static void main(String args[]){
		System.out.println(args[0]);
		System.out.println(args[1]);
		System.out.println(args[2]);
	}
}

练习11:将AllTheColorsOfTheRainbow改写成一个程序

//AllTheColorOfTheRainbow.java
public class AllTheColorOfTheRainbow{
	static int anIntegerRepresentingColors;
	void changeTheHueOfTheColor(int newHue){
		System.out.println("Java中的命名规范");
	}
	public static void main(String args[]){
		//这里可以访问非静态方法的原因是创建了对象
		AllTheColorOfTheRainbow a = new AllTheColorOfTheRainbow();
		a.anIntegerRepresentingColors = 1;
		System.out.println(a.anIntegerRepresentingColors);
		a.changeTheHueOfTheColor(1);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值