现在的位置: 首页 > 综合 > 正文

java学习笔记《java面向对象编程》——数据类型和变量

2018年01月25日 ⁄ 综合 ⁄ 共 8646字 ⁄ 字号 评论关闭

1、Java语言把数据类型分基本类型和引用类型。

一、先介绍基本数据类型,八种基本数据类型,boolean(一个字节)、byte(一个字节)、short(两个字节)、int(四个字节)、long(八个字节)、char(两个字节)、float(四个字节)、double(八个字节)。

在计算他们的取值范围的时候,要注意,它们是带符号的整数,所以首位是符号位,以byte为例,byte一个字节,八位,除去符号位共七位,所以byte类型的数据范围是-128~127。。。依此类推。

boolean类型

boolean类型的变量的取值只能是true或false。java虚拟机对boolean的处理比较特别。当Java编译器把Java源代码编译为字节码时,会用int或byte来表示true。当然,java虚拟机这种底层处理方式对java源程序是透明的。在Java源程序中,不允许把整数或null赋值给boolean类型的变量,这是有别于其他高级语言(如C语言)的地方。这里的规定,感觉java更规范一些。

byte、short、int和long类型

byte、short、int和long都是整数类型,并且都是有符号整数。

在定义一个变量时,到底选用哪种数据类型,要同时考虑实际需求和程序的性能。在内存资源充足的情况下,对于整数变量,通常都把它定义为int类型,这样可以简化数学运算时强制类型转换操作。而在内存资源紧缺的情况下,就必须谨慎的在简化编程和节省内存空间之间进行权衡。

在Java语言中,如果数学表达式中都是整数,那么表达式的返回值只能是int类型和long类型,如果把返回值赋给byte类型的变量,就必须进行类型的强制转换。   

如果一个整数值在某种整数类型的取值范围内,就可以把它直接赋值给这种类型的变量,否则必须进行强制类型的转换。例如:byte b=13;byte a=(byte)129;//变量a的值为-127  因为129不在byte的取值范围内,所以强制转换,这时候的转换都是截断的转换,转换出来的大多没什么意义。

如果在一个整数后面加上后缀——大写“L"或小写”l“就表示它是一个long类型的整数。这并不意味着给long类型的变量赋值的整数后面必须要加上L或l,long a=12;也是可以的,这里12L加上L只是为了赋值匹配,声明类型和实际类型一致,为什么12也可以呢,因为12默认是个是个int类型的,赋值给long类型的变量时,发生自动的类型转换。

java语言允许把八进制(以"0"开头)、十六进制(以”ox“开头)和十六进制数赋给整数类型变量,例如 int a1=012;int a2=0x12;

char类型与字符编码

char是字符类型,Java语言对字符采用Unicode字符编码。Java语言把字符同时作为无符号整数对待,取值范围是0~2^16-1.以下四种方式是等价的。

char c=‘老’; char c='\u8001'; char c=0x8001; char c=32769;

Java编程人员在给字符变量赋值时,通常直接从键盘输入特定的字符,一般不会使用Unicode字符编码,因为很难记住各种字符的Unicode字符编码。但对于有些特殊字符,比如单引号,直接从键盘输入该字符会导致编译错误。这时候我们就需要转义字符了。\ 表示转义字符,其中,\n 换行符,将光标定位在下一行的开头,\t 垂直制表符,\r 回车,将光标定义在当前行的开头,不会跳到下一行 \\代表反斜杠字符  \' 代表单引号字符 \" 代表双引号字符 。在这里,试验了一下,\n 和\r作用一致,都会回车换行的,这里记住一点吧,回车的意思是,回到当前开头,换行的意思是换到下一行。不通的操作系统对这两个字符的处理不同,有的两个合并到一个里了,有的没有。Unix系统里,每行结尾只有“<换行>”,即“\n”;Windows系统里面,每行结尾是“<换行><回车>”,即“\n\r”;Mac系统里,每行结尾是“<回车>”。一个直接的后果是,Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。

float和double类型

Java支持两种浮点类型的小数。

float:占四个字节,共32位,称为单精度浮点数。 double:占八个字节,共64位,称为双精度浮点数。

其他的介绍等看完计算机组成原理再写吧,现在不怎么懂了。

二、接下来介绍引用类型,引用类型分为类引用类型、接口引用类型和数组引用类型。

不管何种类型的变量,它们引用的都是对象。如果一个引用类型的变量不引用任何对象,可以给它赋值为null。在初始化一个引用类型的变量时,常常给它赋初值为null。对于以下代码:

Doll beibei=new Doll("beibei");变量beibei是”Doll类引用类型“的变量,而用new语句创建的Doll对象属于"Doll"类型”。

基本类型仅表示数据类型,而引用类型所引用的实例除了表示复杂数据类型以外,还能包括操纵这种数据类型的行为。Java虚拟机处理引用类型变量和基本类型变量的方式是不一样的:对于基本数据类型的变量,Java虚拟机会为其分配数据类型实际占用的内存空间;而对于引用类型变量,它仅仅是一个指向堆区中某个实例的指针。引用变量本身也占一定的内存空间,到底占用多少内存空间取决于Java虚拟机的实现,这对Java程序是透明的。应该是一个地址所占的空间,32位系统则4字节,64位系统则8字节。

Java语言用new关键字创建对象,他有一下作用:

1、为对象分配内存空间,将对象的实例变量自动初始化为其变量类型的默认值。

2、如果实例变量在声明时被显示初始化,那就把初始值赋给实例变量。

3、调用构造方法。

4、返回对象的引用。

以下是一个Sample类的源程序。

public class Sample{
	int memberV1;
	int memberV2=1;
	int memberV3;
	public Sample(){//构造函数
		memberV3=3;
	}
	public static void main(String args[]){
		Sample obj=new Sample();
	}
}

Java虚拟机执行语句Sample obj=new Sample()的步骤如下。

(1)为一个新的Sample对象分配内存空间,它所有的成员变量都被分配了内存空间,并自动初始化为其变量类型的默认值。

(2)显示初始化memberV2变量,把它的值设为1。

(3)调用构造方法,显示初始化成员变量memberV3。

(4)将对象的引用赋值给变量obj。

一个对象可以被多个引用变量引用。

下面介绍变量的作用域

变量的作用域表明了变量的作用范围,也决定了它的生命周期。

根据作用域的不同,变量可以分为以下类型:

(1)成员变量:在类中声明,它的作用域是整个类。

(2)局部变量:在一个方法的内部或方法的一个代码块的内部声明。作用域是整个方法或者某个代码块。

(3)方法参数:方法或者构造方法的参数,它的作用域是整个方法或者构造方法。

(4)异常处理参数:异常处理参数和方法参数很相似,差别在于前者是传递参数给异常处理代码块,而后者是传递参数给方法给方法或者构造方法。

成员变量的生命周期:成员变量根据有无static修饰分为静态变量和成员变量。二者的区别在于:

A:类的静态变量在内存中只有一个,Java虚拟机在加载类的过程中为静态变量分配内存,静态变量位于方法区,被类的所有实例共享。静态变量可以直接通过类名来访问。静态变量的生命周期取决于类的生命周期,当加载类的时候,静态变量被创建并分配内存,当卸载类的时候,静态变量被销毁并撤销所占内存。

B:类的每个实例都有相应的实例变量。每创建一个类的实例,Java虚拟机就会为实例变量分配一次内存,实例变量位于堆区中。实力变量的生命周期取决于实例的声明周期,当创建实例的时候,实例变量被创建并分配内存,当销毁实例的时候,实例变量被销毁并撤销所占内存。

值得注意的一点是:对于成员变量是引用变量的情况,当该成员变量结束生命周期的时候,并不意味着它所引用的对象结束生命周期。

静态变量既可以通过引用变量来访问,也可以通过类名来访问。静态变量可以作为所有实例的共享数据,它不依赖于特定的实例;而实例变量属于特定的实例。

局部变量的生命周期:局部变量的生命周期取决于它所属的方法何时被调用及结束调用。

当Java虚拟机(更确切的说,是Java虚拟机的某个线程)调用一个方法时,会为这个方法的局部变量分配内存。

当java虚拟机(更确切的说,是Java虚拟机的某个线程)结束调用一个方法时,会结束这个方法的局部变量的生命周期。

举例说明一下:

public class Sample{
	int var1=1;//var1是实例变量
	static int var2=2;//var2是静态变量
	public int add(){
		int var3=var1+var2;//var3是局部变量
		return var3;
	}
	public int delete(){
		int var4=var1-var2;//var4是局部变量
		return var4;
	}
	public static void main(String args[]){
		new.Sample().add();
	}
}


当执行“java Sample”命令时,Java虚拟机执行一下流程。

(1)加载Sample类,开始静态变量var2的生命周期,var2位于方法区。

(2)创建Sample实例,开始实例变量var1的生命周期,var1位于堆区。

(3)调用Sample实例的add()方法,开始局部变量var3的生命周期,var3位于Java栈区。

(4)执行完毕Sample实例的add()方法,结束局部变量var3的声明周期,退回到main()方法。

(5)执行完毕Sample类的main()方法,结束Sample实例及它的实例变量var1的声明周期,卸载Sample类,结束静态变量var2的声明周期,Java虚拟机运行结束。

由于man()方法没有调用Sample实例的delete()方法,因此var4变量在Java虚拟机的运行过程中没有被创建过。其实在这里还有问题,局部变量在方法结束的时候结束生命周期已经很明白了,但是成员变量和静态变量结束依赖对象的销毁和类的卸载,假如main()方法没有结束,那么对象的销毁和类的卸载发生在什么时候。

由于局部变量和成员变量有着完全不同的生命周期,在使用局部变量的时候,收到以下限制:

A:局部变量不能被static、private、protected和public等修饰符修饰。

B:不能通过类名或者引用名来访问局部变量。

成员变量和局部变量同名

在同一个作用域内不允许定义同名的许多变量,如果不在同一个作用域里就可以定义同名变量。

在一个方法内,可以定义和成员变量同名的局部变量或参数,此时成员变量被屏蔽。此时如果要访问实例变量,可以通过this关键字来访问,this作为当前实例的引用。如果要访问类变量就通过类名来访问。

这里分析一下:因为成员变量的作用域是整个类,包括了和该成员变量同名的变量所在的方法,大范围包含了小范围,这样就会有交集,这时候需要通过this来引用被屏蔽的成员变量。注意这种情况只能发生在成员变量和局部变量同名的时候,局部变量内部,即使是大范围和小范围内也不允许发生同名,否则会编译错误,重定义了。

作为程序员应该注意的是,将局部变量的作用域最小化。过早的定义局部变量会造成一下负面影响:

(1)程序的可读性和可维护性差。分散阅读程序的开发人员的注意力,当该变量被使用的时候,可能开发人员已经忘记了该变量是在哪里定义的了。

(2)增加出错的可能性。该变量可能在其他地方被错误的使用。

为此,我们应该在需要使用某局部变量的时候,才定义它,并且使方法小而集中。方法小了,局部变量的作用域也就自然变小了。对象的默认引用:this

当一个对象创建好后,Java虚拟机就会给它分配一个引用自身的指针:this。所有的对象默认的引用名都是this。java虚拟机如何区分这些同名的this呢?总结起来就一句话:谁调用了包含this的方法,谁就是该方法中this所代表的对象。

在程序中,在以下情况下会使用this关键字:

(1)在类的构造方法中,通过this语句调用这个类的另一个构造方法。

(2)在一个实例方法内,局部变量或参数和实例变量同名,实例变量别屏蔽,因此采用this.owner的方式来指代实例变量。

(3)在一个实例方法内,访问当前实例的引用。这种情况就是利用了对象的默认引用this,适合那句总结:谁调用了包含this的方法,谁就是该方法中this所代表的对象。

值得注意的是:只能在构造方法或者实例方法中使用this关键字,而在静态方法和静态代码块内不能使用this关键字。这里也好理解,因为上述出现this的三种情况下,首先,构造方法不会是静态方法也不会出现在静态代码区中,第二,静态方法和静态代码区中不会用到实例变量(非静态变量),不会用到this,第三,访问当前类的引用,静态方法和静态代码块是再类加载的时候被处理的,那时候不可能产生对象,所以也不会用到this,所以在静态方法和静态代码中不会用到this,this不允许出现在静态方法和静态代码区中。?

参数传递

如果方法A调用方法B,那么称方法A是方法B的调用者。如果方法B的参数是基本数据类型,那么方法A向方法B传递参数的值。如果方法B的参数是对象或数组,那么方法A向方法B传递对象或数组的引用。

每当用java命令启动一个java虚拟机进程时,java虚拟机就会创建一个主线程,该线程从程序入口main()方法开始执行。主线程在java栈区内有一个方法调用栈,每执行一个方法,就会向方法栈中压入一个包含该方法的局部变量及参数的栈帧。

public class ParamTester{
  public int memberVariable=0;


  public static void main(String args[]){


    //声明并初始化4个局部变量
    int param1=0; // param1是基本数据类型
    ParamTester param2=new ParamTester(); //param2 是对象引用类型
    ParamTester param3=new ParamTester();//param3 是对象引用类型
    int[] param4={0}; //param4是数组引用类型
		
    //将4个局部变量作为参数传递给changeParameter()方法
    changeParameter(param1, param2, param3, param4);					
    //打印4个局部变量
    System.out.println("param1=" +param1);
    System.out.println("param2.memberVariable="+param2.memberVariable);                 
    System.out.println("param3.memberVariable=" + param3.memberVariable);
    System.out.println("param4[0]="+param4[0]);
  }


  public static void changeParameter(int param1, ParamTester param2, ParamTester   
                                   param3, int[] param4){
    param1=1; //改变基本数据类型参数的值
    param2.memberVariable=1; //改变对象类型参数的实例变量
    param3=new ParamTester();  //改变对象类型参数的引用,使它引用一个新的对象
    param3.memberVariable=1; //改变新的对象的实例变量
    param4[0]=1; //改变数组类型参数的元素
  }
}


/****************************************************
 * 作者:孙卫琴                                     *
 * 来源:<<Java面向对象编程>>                       *
 * 技术支持网址:www.javathinker.org                *
 ***************************************************/

打印结果:四个变量的值分别是 0 1 0 1

解释一下:

(1)成员变量param1是0,changeParameter方法中方法参数也是param1(局部变量),恰好同名,这时changeParameter方法传参数param1进去,传进去的只是param1的值,方法里面对局部变量param1所作的任何修改,方法结束之后,不会对成员变量param1造成任何影响,所以一个变量的值是0;

(2)changeParameter方法将param2的引用传进去了,并且修改了param2的属性值,相当于直接修改了param2,所以方法结束之后,打印出修改后的结果,是1;

(3)虽然changeParameter方法将param3传进去了,但是局部的引用变量param3在方法里面引用了新的对象,这时候对param3所做的任何修改就和成员变量param3没关系了,所以方法结束之后,成员变量param3没发生改变,所以打印结果是0;

(4)数组类型的参数也是引用变量,所以changeParameter也将param4传进去了,然后方法里面对param4进行了修改,方法结束之后,成员变量param4发生了改变,所以打印结果是1;

变量的初始化及默认值

Java语言要求遵循先定义,再初始化,然后使用的规则。变量的初始化是指自从变量定义之后,首次给它赋初值的过程。

(1)成员变量的初始化

对于类的成员变量,不管程序有没有显示地进行初始化,Java虚拟机都会先自动给它初始化为默认值。

byte、short、int和long的基本类型变量的默认值是0;

float基本类型变量的默认值是0.0f;

double基本类型变量的默认值是0.0d;

char基本类型变量的默认值为”\u0001“;

boolean基本类型变量的默认值是false;

引用类型的变量的默认值是null;

数组引用类型的变量的默认值为null。

(2)局部变量的初始化

局部变量声明之后,Java虚拟机就不会自动给它初始化为默认值。因此对于局部变量,必须先经过初始化,才能使用。对于成员变量,Java语言提供了多种初始化的途径,既可在声明时初始化,也可在构造方法中初始化(适用于实例变量),还可在静态代码块中初始化(适用于静态变量),加入成员变量的初始值与该数据类型的默认值不符,程序员一般总会在构造方法中显示给它初始化。

直接数

直接数是指直接给变量赋值的具体数值。

(1)对于基本数据类型的数据,除了byte和short类型之外,都有相应的直接数。

(2)对于整数,如果在int类型的取值范围之内,就是int型直接数,否则,如果在long类型的取值范围之内,就是long型直接数。

(3)对于long、float和double型直接数,可以分别加上后缀:L或l、F过f,以及D或d。

(4)如果一个小数没有任何后缀,那么它是double型直接数,用十进制科学技术法表示的数字都是double型直接数。

(5)对于引用类型,只有String类型有直接数。

直接数的赋值

l 基本类型直接数不允许赋给String类型,同样,String类型的直接数也不允许赋给基本类型的变量。

l boolean类型的直接数只能周期给boolean类型的变量,boolean类型的变量只接受boolean类型的直接数。

l 把int类型的直接数赋给byte、short或char类型变量时,如果直接数位于该变量类型取值范围内,就允许直接赋值,否则必须进行强制类型转换。

l long类型的直接数赋给其他整数型变量时,都需要强制类型转换,符合下面的总原则,int没有严格符合总原则。

l 把float型和double型直接数赋给整型变量时,必须经过强制类型的转换,而把整数型直接数赋给float型和double型变量时,允许直接赋值。

l 把double型直接数赋给float类型变量时,必须经过强制类型的转换,而把float类型直接数赋给double类型变量时,允许直接赋值。

基本数据类型数据赋值的总原则是,取值范围小得数据类型允许直接赋给取值范围大的数据类型。

附表:

数据类型

关键字

在内存中占用字节数

取值范围

默认值

布尔型

boolean

1

true,false

false

字节型

byte

1

-128~127

0

短整型

short

2

-215 ~ 215-1

0

整型

int

4

-231 ~ 231-1

0

长整型

long

8

-263 ~ 263-1

0

字符型

char

2

0 ~ 216-1

‘\u0000’

单精度浮点型

float

4

1.4013E-45 ~ 3.4028E+38

0.0F

双精度浮点型

double

8

4.9E-324 ~ 1.7977E+308

0.0D


抱歉!评论已关闭.