该系列文章系个人读书笔记及总结性内容,任何组织和个人不得转载进行商业活动!
第三章:primitive主数据类型和引用-认识变量
认识变量:
变量有两种:primitive(简单的)主数据类型和引用;
目前我们已经使用过变量的地方:对象的状态(instance variables)与局部(local)变量(声明在方法中的变量);
后续我们会发现,变量还可以用作参数(arguments,传递给方法的值)及返回值类型(执行方法所返回的值);
我们已经看过被声明成primitive整数值(int)的变量以及声明成更复杂的类型的变量(String和数组);当然可能还有更复杂的,本章让我们探索Java类型:变量的声明以及如何运用变量;最后还会看到垃圾可回收的堆;
声明变量:
Java注重类型,他不会让你将浮点数类型变量放进整数类型的变量中;(除非确认可以损失精度)
Rabbit hopper = new Giraffe();//不能把长颈鹿的变量放进装进兔子的变量中;这句通过不了编译;
为了让类型安全发挥作用,必须声明所有变量的类型;
变量有两种口味:
清新的primitive主数据类型;用来保存基本数据类型;
香辣的对象引用;用来保存对象的引用;
声明变量的规则:
必须拥有类型;
必须拥有名称;
变量就像杯子,是一种容器;有大小和类型;
对于primitive主数据类型有各自不同的大小(固定的位数)和名称;
boolean:位数由虚拟机决定 true/false;
char:16 bits;
byte:8 bits;正负
short:16 bites;正负
int:32 bits;正负
long:64 bits;正负
float:32 bits;范围规模可变
double:64 bits;范围规模可变
赋值示例:
char c = ‘f’;
float f = 32.5f;//除非加f,否则所有小数点的值都会被Java当做double处理;
赋值时需要确保变量能存下所保存的值;
无法用小杯子装大值,好吧,其实也可以,但会损失某些信息,也就是所说的“溢位”;所以这种方式编译器是不允许的;
比如:int x = 24;把他赋给byte b = x;的时候就无法通过编译,虽然byte能放得下24,但在编译器看来是将大物体装进小容器,可能会溢位;
编译器不许大杯的内容放进小杯,但反过来可以;
给变量赋值的几种方式:
在等号后直接赋值;x=1;
指派其他变量的值;x=y;
上述两种组合;x=y+1;
避开关键字(keyword):
命名的方法:以下规则帮助类、方法和变量命名(实际规则可能个复杂);
名称必须以字母、下划线(_)或$符号开头,不能用数字开头;
除第一个字符之外,后边可以用数字;
符合上述两条,还要避开保留字;
保留字是编译器要辨别的关键字;
primitive主数据类型变量的声明及赋值,那非primitive主数据类型的变量呢?即对象要如何处理?
事实上没有对象变量这样的东西存在;
只有引用(reference)到对象的变量;
对象引用变量保存的是存取对象的方法;
它并不是对象的容器,而是类似指向对象的指针;但在Java中我们不会也不该知道引用变量中实际的装载,他只是用来代表单一的对象;只有JVM才会知道如何使用引用来取得该对象;
你无法将变量装进变量中;对象只会存在于可回收垃圾的堆上;
虽然primitive主数据类型变量是以字节来代表实际的变量值;但对象引用变量却是以字节来表示取得对象的方法;
控制Dog对象:
Dog d = new Dog();
d.bark();//把“d”想象成遥控器,即把Dog的引用变量想象成Dog的遥控器,通过它来执行工作;
使用圆点运算符(.)来对引用变量表示:“取得圆点前面的对象,然后求出该对象在圆点后面的事物”;
d.bark()就可以代表名为d的变量引用对象上的bark();类似遥控器与按钮的关系;
对象引用也只是个变量值:
reference与primitive主数据类型不同(若干bits),reference与对象大小无关;
还是会有东西放进杯子中,只是引用所放进去的是遥控器(对象的引用);
示例:
byte x = 7;//代表数值7的字节被放进变量中(00000111);
Dog d = new Dog();//代表取得Dog对象的方法以字节形式放进变量中;(对象本身并没有放进变量中)
对primitive主数据类型中的变量来说,变量值就是所代表的值;
对引用变量来说,变量值是取得特定对象的位表示法;
对象的声明、创建与赋值有3个步骤:
1)声明一个引用变量;-要求JVM分配空间给引用变量,命名并确定类型;
2)创建对象;-要求JVM分配堆空间给新建的对象;
3)连接对象与引用;-将对象赋值给引用变量(设定遥控器);
采访对象引用(object reference):
我只是个遥控器,可以被设定来控制不同的对象;
被声明成什么就是什么,不能指向当前声明类型以外的事物;
我可以被转换指向同一类型的其他对象;就像重新设定遥控器一样;
如果被标记成final,一旦被指定给某个对象就不能再赋值其他对象了,同一类型的也不行,也就是说被固定了;
能够引用到空指针null,即不引用任何东西;
虽然null也是个值,但这毫无意义,更糟的是,如果是某个对象的唯一引用却又被设定成null,这意味着之后将没有其他人能够取得该对象;
知识小问答:
引用变量有多大?
不知道,除非JVM的开发告诉你,不然你不会知道引用如何表示;其内部有指针,但你也不需要存取;
若讨论内存分配问题,需要关心的也是需要建立多少个对象和引用,以及对象的实际大小;
那是不是说引用都具有相同大小,而不管他实际上所引用的对象大小?
是的;对于同一JVM来说,所有引用大小都一样,不同JVM之间可能会有差别;
我可以对引用变量进行运算吗?像C语言那样?
不行,Java不是C;
垃圾收集堆上生活:
垃圾收集堆上的一个对象可以有多个引用,就行一台电视可以有多个遥控器;
当对象没有引用时,也就无法存取,就会被抛弃且能够作垃圾收集器(GC);
将引用变量设置为null表示它不再引用任何事物;
在看数组:
数组如同杯架,int数组的每个元素皆是int类型的变量;
数组也是对象:
Java标准函数库中有许多数据结构如map、tree和set;
但如果需要快速、有序、高效的排列元素,数组更合适;
数组能够让你使用位置索引来快速、随机地存取其中的元素;
存储对象的数组的元素持有的是对对象的引用;
而且数组是个对象,不管里边方的是什么类型的数据;
示例:
Dog[] ds = new Dog[10];
ds[0] = new Dog();//使用Dog对象为Dog数组的元素(引用)赋值
……
ds[0].bark();
Java注重类型:
一旦数组被声明出来,就只能装入所声明类型的元素;编译器会根据数组所声明的类型来防止错误的类型;
int[]数组可以放byte类型的数据,这种被称为‘隐含展开’(implicit widening);
示例(Code-Dog.java)
class Dog{
String name;
public void bark(){
System.out.println(name + " say hello!");
}
public static void main(String[] args){
Dog dog1 = new Dog();
dog1.bark();
dog1.name = "Bart";
Dog[] myDogs = new Dog[3];
myDogs[0] = new Dog();
myDogs[1] = new Dog();
myDogs[2] = dog1;
myDogs[0].name = "Fred";
myDogs[1].name = "Marge";
System.out.println(myDogs[2].name + " say hello!");
int x = 0;
while(x < myDogs.length){
myDogs[x].bark();
x = x + 1;
}
}
}
log:
bogon:180131-第三章 huaqiang$ javac Dog.java
bogon:180131-第三章 huaqiang$ java Dog
null say hello!
Bart say hello!
Fred say hello!
Marge say hello!
要点:
变量有两种:primitive主数据类型和引用;
变量声明必须有类型和名称;
primitive主数据类型变量值是该值的字节所表示的;
引用变量的值代表位于堆之对象的存取方法;
引用变量如同遥控器,对引用变量使用圆点运算符可以如同按下遥控器按钮般地存取它的方法或实例变量;
没有引用到任何对象的引用变量的值为null值;
数组一定是对象;(没有primitive主数据类型的数组,只有装载primitive主数据类型的数组);