---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

黑马程序员-------------(一)Java基础知识

目录

一 Java概述

二 Java语言基础

    1.关键字

    2.标识符

    3.注释

    4.常量和变量

    5.运算符

    6.语句(程序流程控制)

    7.函数

    8.数组

注:本章重点内容:数据类型;自动类型提升与类型强制转换;自增,自减;“&”和“&&”、“|”和“||”的区别;运算符的优先级;累加思想;计数器思想;函数的重载
和数组的常见操作。对于重点内容,根据知识的重要程度用◆◆◆、◆◆◆◆、◆◆◆◆◆进行了标注。


####################################################################################
一 Java概述
####################################################################################

1.什么是Java?
Java具有三个方面的内涵:是一种编程语言;是一套开发工具;是一个运行环境。
Java语言是SUN(Stanford University Network)斯坦福大学网络公司1995年推出的一门高级编程语言。简单易学,完全面向对象,安全可靠,与平台无关,是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。

2.Java语言

(1)特点:跨平台性。即一次编译,到处运行

(2)Java运行和开发工具
JVM(Java Virtual Machine)Java虚拟机,负责Java程序在系统中的运行。
JRE(Java Runtime Environment)Java运行环境,包括Java虚拟机(JVM Java Virtual Machine)和Java程序所需的核心类库等。
JDK(Java Development Kit)Java开发工具包,提供给Java开发人员使用的,其中包含了Java的开发工具。
JDK包含了JRE,JRE包含了JVM。

(3)三种技术架构
JAVA EE(Java Platform Enterprise Edition)企业版,为开发企业环境下的应用程序提供的一套解决方案,该技术体系主要针对于Web应用程序开发.
JAVA SE(Java Platform Standard Edition)标准版,为开发普通桌面和商务应用程序提供的解决方案。该技术体系是其他两者的基础,
JAVA ME(Java Platform Micro Edition)小型版,为开发电子消费产品和嵌入式设备提供的解决方案。该技术体系主要应用于小型电子消费类产品。

3.Java语言的环境搭建
我的系统是64位的win8专业版,依此为例:

(1)path环境变量配置(在任意路径下可以执行javac命令)
方法一:永久配置方式
依次选择鼠标右键单击计算机->属性->高级系统设置->环境变量。在系统变量里找到并编辑path环境变量,在变量值开始处加上java工具所在目录,后面用“;”和其他值分隔开即可。
方法二:临时配置方式
通过dos命令中的set命令完成。打开dos命令行,输入set path=javac命令所在地址目录。如果想要在原有环境变量值基础上添加新值,可以set path=新值;%path%。

(2)classpath环境变量配置(在任意路径下可以执行某一路径下的class文件或包中的class文件)
方法一:永久配置方式
依次选择鼠标右键单击计算机->属性->高级系统设置->环境变量。在系统变量选项卡里点击新建,变量名为classpath,变量值为class文件路径。
方法二:临时配置方式
通过dos命令中set命令完成。打开dos命令行,输入set classpath=class文件路径。


注意:
a.path和classpath的临时配置方式都是只在当前dos窗口有效。窗口关闭,配置消失。
b.对于classpath来说,不仅可以执行该路径下的class文件,也可以执行该路径下所有包中的class文件。
c.等号两边不能有空格,否则就是一个新的环境变量了。如set path=aa和set path =aa代表的就是两个环境变量path和path 。


(3)path和classpath的区别:
path变量值是windows程序文件的目录。在dos命令行中执行某一程序时,windows系统先在当前目录下找当前执行的程序,如果没有再去系统中
已有的一个名为path的环境变量指定的路径下找,如果都没有就会出现错误提示。classpath变量值是java类文件的目录。在dos命令行中运行某一个类时,如果没有配置classpath,JVM只在当前目录下找要运行的类文件;如果配置了classpath,JVM会先在classpath路径下找(结尾没有分号,只在classpath路径下找;结尾有分号,先在classpath路径下找,如果没有再去当前目录下找)。

建议:
在配置classpath环境变量时,值的结尾处不要加分号,如果需要访问当前目录可以用“.”表示。


####################################################################################
二 Java语言基础
####################################################################################

Java语言基础组成
关键字,标识符,注释,常量和变量,运算符,语句,函数和数组。

1.关键字

定义:被Java语言赋予了特殊含义的单词
特点:关键字中所有字母都为小写

这些关键字将在以后用到的时候逐一进行介绍。

2.标识符

定义:在程序中自定义的一些名称。
组成:由26个英文字母大小写,数字0-9,符号_和$组成
定义合法标识符规则:(1)数字不可以开头。(2)不可以使用关键字。
Java中的名称规范:
包名-------------多单词组成时所有字母都小写:xxxyyyzzz。
类名接口名-------多单词组成时,所有单词的首字母大写:XxxYyyZzz。
变量名和函数名---多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZzz。
常量名-----------所有字母都大写。多单词时每个单词用下划线连接:XXX_YYY_ZZZ。

3.注释

定义:用于注解说明解释程序的文字
作用:增加阅读性;调试程序。
格式:
单行注释格式: //注释文字
多行注释格式: /*  注释文字  */
文档注释格式: /** 注释文字 */
对于单行和多行注释,被注释的文字,不会被JVM执行。对于文档注释,是Java特有的注释,其中注释内容可以被JDK提供的工具javadoc所解析,
生成一套以网页文件形式体现的该程序的说明文档。单行注释和多行注释中可以加入单行注释,多行注释中不能加入多行注释。

4.常量和变量

4.1 常量
定义:常量表示不能改变的数值

4.1.1 Java中常量的分类:
(1)整数常量----------所有整数
(2)小数常量----------所有小数
(3)布尔型常量--------较为特有,只有两个数值 true false
(4)字符常量----------将一个数字字母或者符号用单引号标识
(5)字符串常量--------将一个或者多个字符用双引号标识
(6)null常量----------只有一个数值 null

4.1.2 对于整数:Java有四种表现形式:
二进制--------0-1,满2进1。
十进制--------0-9,满10进1。
八进制--------0-7,满8进1。用0开头表示。3个二进制位代表一个八进制位。
十六进制------0-9,A-F,满16进1. 用0x开头表示。4个二进制位代表一个十六进制位。

4.2 变量
变量的概念:变量是内存中的一个存储区域,该区域有自己的名称(变量名)和类型(数据类型),该区域的数据可以在同一类型范围内不断变化。
定义变量的格式:数据类型 变量名=初始化值;

◆◆◆【4.2.1 数据类型】◆◆◆
Java语言是强类型语言,对于每一种数据都定义了明确的具体数据类型,在内存中分配了不同大小的内存空间。



一个字节由8个二进制位表示。
byte--------用一个字节表示,  字节,范围-128~127,即-2(7)~2(7)-1
short-------用两个字节表示,短整型,范围-32768~32767,即-2(15)~2(15)-1
int---------用四个字节表示,  整型,范围-2(31)~2(31)-1。Java中整数默认:int
long--------用八个字节表示,长整型,用于天文数字
float-------用四个字节表示,单精度,
double------用八个字节表示,双精度,Java中小数默认:double    
char--------用两个字节表示,取值范围0~65535。
boolean-----用一个字节表示,取值只有两个。 true,false

◆◆◆【4.2.2 自动类型提升与类型强制转换】◆◆◆
自动类型提升,也叫自动类型转换或隐式类型转换;强制类型转换,也叫显式类型转换。

(1)精度从高到低  double>float>long>int>short(char)>byte
自动类型转换:将一个低精度变成高精度
强制类型转换:将一个高精度变成低精度(精度会下降)
(2)表达式的数据类型自动提升
所有的byte型、short型和char的值将被提升到int型。
如果一个操作数是long型,计算结果就是long型;
如果一个操作数是float型,计算结果就是float型;
如果一个操作数是double型,计算结果就是double型。
(3)范例
byte b = 3;b = b + 2;
编译失败,因为2作为整数默认int型,计算机在对b和2进行加法运算时会自动把b提升为int型,得到的结果也是int型,在向b赋值时会报错。
byte b = 3;b = (byte)(b+2);
编译通过。在这里b先进行自动类型提升,与2进行加法运算后的数据为int型,被byte强制转换为byte类型后赋值给b。
byte b = 3;int x = 4;x = x + b;
编译通过。b会自动提升为int类型进行运算。得到的结果也是int类型,赋值给int类型的x没有问题。
byte a=3,b=4,c;c=a+b;
编译失败,因为a和b是变量,因为变量的值会变化,不确定具体的值,所以默认使用int类型进行存储。
byte a=3,b=4,c;c=3+4;
编译通过。因为3和4是常量,所以java在编译时期会检查该常量的和是否超出byte类型的范围。如果没有就赋值。
short s = 3;s=s+2;
编译失败,因为s会被提升为int类型,运算后的结果还是int类型。无法赋值给short类型。是两次运算,先做加法,再做赋值,不会做自动转换.
short s = 3;s+=2;
编译通过,因为+=运算符在给s赋值时,自动完成了强转操作。是一次运算。

4.2.3 将两个int型变量的值互换的方法

方法一:通过第三方变量。
        int temp;
        temp = n;
        n = m;
        m = temp;

方法二:不用第三方变量。如果n和m的值非常大,容易超出int范围。
        n = n + m;
        m = n - m;//m=(n+m)-m=n;
        n = n - m;//n=(n+m)-((n+m)-m)=m;

方法三:不用第三方变量,通过异或
        n = n ^ m;
        m = n ^ m;//m=(n^m)^m=n;
        n = n ^ m;//n=(n^m)^((n^m)^m)=m;

5.运算符

5.1 算术运算符



(1)对于除号“/”,它的整数除和小数除是有区别的:整数之间做除法时,只保留整数部分而舍弃小数部分。
int x=3510;
x=x/1000*1000;
实际运行结果是3000 ,

(2)% 取模,即求余数
规律:
左边小于右边,结果是左边;左边等于右边,结果是0;右边是1,结果是0;出现负数,只看左边(被模数)。
4%2=0,5%2=1,5%4=1,5%1=0,1%5=1,5%5=0,1%-5=1,-1%5=-1

◆◆◆◆【(3)++,-- 自增,自减】◆◆◆◆
b=a++;  a先赋值给b,然后进行自增运算。
b=++a;  a先进行自增运算,然后赋值给b。
a=a++;  a先赋值给a,然后进行自增运算(无论运算多少次,a的值不变)
a=++a;  a先进行自增运算,然后赋值给a(相当于a++)
b==++a; a先进行自增运算,然后判断与b是否相等。
b==a++; a先判断与b是否相等,然后进行自增运算。
a++>b;  a先判断是否大于b,然后进行自增运算。
++a>b;  a先进行自增运算,然后判断是否大于b。

(4)+ 字符串相加
字符串数据和任何数据使用+都是相连接,最终都会变成字符串
System.out.println(“ab”+5+5);        打印结果ab55
System.out.println(“5+5=”+5+5);        打印结果5+5=55
System.out.println(“5+5=”+(5+5));    打印结果5+5=10(提高了优先级)

(5)\ 转义字符
通过“\”来转变后面字母或符号的意义,转义字符要写在被转义字符前面
\n:换行。
\t:制表符。相当于tab键。
\b:退格。相当于backspace。
\r:按下回车键。window系统,回车符是由两个字符来表示\r\n.
System.out.println(“\”hello\””);    打印结果“hello”
System.out.println(“\\hello\\”);    打印结果\hello\

5.2 赋值运算符


+= 加等于。把左右两边的和赋值给左边。
short s = 3;s=s+2;
编译失败,因为s会被提升为int类型,运算后的结果还是int类型。无法赋值给short类型。是两次运算,先做加法,再做赋值,不会做自动转换动作;
short s = 3;s+=2;
编译通过,因为+=运算符在给s赋值时,自动完成了强转操作。是一次运算。

5.3 比较运算符


比较运算符的结果都是boolean型,也就是要么是true,要么是false。

5.4 逻辑运算符
     

(1)逻辑运算符用于连接布尔型表达式,
&:两边只要有一个为false。结果为false。只有两边都为true,结果为true。
|:两边只要有一个为true,结果为true。只有两边都为false,结果为false。
^:两边相同结果是false。两边不同结果是true。

◆◆◆◆【(2)“&”和“&&”、“|”和“||”的区别:】◆◆◆◆
&    左边无论真假,右边都进行运算;
&&    如果左边为假,那么右边不参与运算。
|    左边无论真假,右边都进行运算;
||    如果左边为真,那么右边不参与运算。

5.5 位运算符

<<:被移除的高位丢弃,空缺位补0,相当于乘与2的移动位数次幂。
>>:被移位的二进制最高位是0,右移后,空缺位补0;最高位是1,空缺位补1。相当于除以2的移动位数次幂。
>>>:被移位的二进制位无论是0还是1,空缺位补0。
&:二进制位进行&运算,只有1&1时结果是1,否则是0。
|:二进制位进行|运算,只有0|0时结果是0,否则是1。
^:任何相同二进制位进行^运算,结果是0;不相同二进制位进行^运算,结果是1。

注意:
a.对于int型整数移位a>>b,系统先将b对32取模,得到的结果才是真正移位的位数。例如:a>>33和a>>1结果是一样的,a>>32的结果还是a原来的数字。对于long型整数移位时a>>b ,则是先将移位位数b对64取模。
b.移位不会改变变量本身的值。如a>>1;在一行语句中单独存在,毫无意义 。
c.x>>1的结果和x/2的结果是一样的,x<<2和x*4的结果也是一样的。总之,一个数左移n位,就是等于这个数乘以2的n次方,一个数右移n位,就是等于这个数除以2的n次方。
d.一个数异或同一个数两次,结果不变,还是原来的数;一个数异或它自己,结果为0;0异或任何数的结果还是原来的那个数;1异或任何数的结果相当于对原来的数取反,效果和~反码一样;


你发现了吗?
如何用程序实现求2的x次方?
答案:y = 1<< x;

5.6 三元运算符
格式:
(条件表达式)?表达式1:表达式2;
如果条件为true,运算后的结果是表达式1;
如果条件为false,运算后的结果是表达式2;

好处与弊端:
好处:可以简化if else代码,写在其他表达式中。
弊端:因为是一个运算符,所以运算完必须要有一个结果。

◆◆◆◆【5.7运算符的优先级】◆◆◆◆


6.语句(程序的流程控制)
6.1 判断结构

(1)if语句格式
格式一
    if(条件表达式)
    {
        执行语句;
    }
格式二
    if(条件表达式)
    {
        执行语句;
    }
    else
    {
        执行语句;
    }
格式三
    if(条件表达式)
    {
        执行语句;
    }
    else if(条件表达式)
    {
        执行语句;
    }
    ……
    else
    {
        执行语句;
    }

(2)if语句特点:
1)每一种格式都是单条语句。
2)条件表达式无论写成什么样子,只看最终的结果是 true 还是 false;
3)如果if控制的只有一条语句,可以不用写{},反过来说,如果if语句后没有{},则只控制离它最近的一条语句。

(3) if else 结构简写格式:
变量=(条件表达式)?表达式1:表达式2;

6.2 选择结构

(1)switch语句格式:
    switch(表达式)
    {
        case 取值1:
            执行语句;
            break;
        case 取值2:
            执行语句;
            break;
        ……
        default:
            执行语句;
            break;
    }

(2)switch语句特点:
1)switch语句选择的类型: byte,short,int,char
2)case之间与default没有先后顺序。先执行第一个case,没有匹配的case执行default。
3)结束switch语句的两种情况:遇到break或者执行到switch语句结束。
4)如果匹配的case或者default没有对应的break,那么程序会继续向下执行,运行所有可以执行的语句,直到遇到break或者switch语句结束。

(3)if和switch的区别
如果判断的具体数值不多,而且符合 byte,short,int,char 这几种类型,虽然两个语句都可以使用,但建议使用switch语句,因为效率稍高.
其它情况:对区间判断,对结果为boolean类型判断,使用if语句,if的使用范围更广。

你发现了吗?
switch语句选择的类型也可以是枚举类型哦!


6.3 循环结构
(1)while语句格式:
    while(条件表达式)
    {
        执行语句;
    }

(2)do while语句格式:
    do
    {
        执行语句;
    }while(条件表达式);

(3)for语句格式:
    for(初始化表达式;循环条件表达式;循环后的操作表达式)
    {
        执行语句;
    }

(4)语句特点:
1)while 特点是先判断条件,只有条件满足才执行循环体。
2)do while 特点是先执行一次循环体,再判断条件,条件满足,再继续执行循环体。条件无论是否满足,循环体至少被执行一次。
3)for 语句里面的各个表达式运行的顺序,初始化表达式只读一次,判断循环条件,为真就执行循环体,然后再执行循环后的操作表达式,接着继续判断循环条件,重复这个过程,直到条件不满足为止。

(5)while和for的区别
for与while可以互换,用for语句能写出的,用while语句一定也能写出。区别在于for为了循环而定义的变量在for循环结束后就在内存中释放。而while循环使用的变量在循环结束后还可以继续使用。对于变量来说,如果该变量仅仅用于控制循环的次数,作为循环增量存在的情况下,用for语句更合适,因为内存被及时释放。

注意:
最简单无限循环格式:while(true) , for(;;),无限循环存在的原因是并不知道循环多少次,而是根据某些条件,来控制循环。

6.4 其他流程控制语句

6.4.1 break(跳出)和 continue(继续)

(1)应用范围:
break    语句:应用于选择结构和循环结构。
continue 语句:应用于循环结构。继续循环

(2)break和continue语句特点:
1)这两个语句必须有作用范围。离开应用范围存在是没有意义的。
2)这两个语句单独存在时,下面都不可以有语句,因为执行不到。
3)continue语句的特点是结束本次循环继续下次循环。

6.5 流程控制的应用

◆◆◆◆◆【6.5.1 累加思想】◆◆◆◆◆
(1)原理:通过变量记录每次变化的结果,通过循环的形式进行累加的动作。变量+循环
(2)代码示例
例:求任意两个整数之间所有整数的和(以1-10之间所有整数的和为例)。
思路:
1)对两个整数之间的整数求和,首先需要先对这两个整数之间的所有整数进行遍历。
2)在遍历过程中,让每一个遍历到的数和前面的和相加,由于这个和的结果是变化的,所以要定义一个变量记住这个和。
3)遍历结束后这个变量中的值就是最终的结果。

 1 class Summation
 2 {
 3     public static void main(String[] args)
 4     {
 5         int sum=getSum(100,1);
 6         System.out.println(sum);
 7     }
 8     //将功能封装成函数,求任意两个整数之间数字的和,就需要传进来两个整数。
 9     public static int getSum(int start,int end)
10     {
11         //定义变量sum存储不断变化的和,定义min等于传进来的较小整数,max等于传进来的较大整数。
12         int sum=0,min,max;
13         min=(start<end)?start:end;
14         max=(min==start)?end:start;
15         
16         //定义一个循环,进行累加的动作。
17         for (int x=min;x<=max ;x++ )
18         {
19             sum+=x;
20         }
21         return sum;
22     }
23 }


◆◆◆◆◆【6.5.2 计数器思想】◆◆◆◆◆
(1)原理:通过变量记录住数据的状态变化,通过循环完成遍历的动作,遍历过程中加入控制变量变化的判断。
(2)代码示例
例:求任意两个整数之间是某个整数倍数的个数(以1-100之间7的倍数的个数为例)。
思路:
1)先对两个整数之间的数进行遍历
2)在遍历的过程中,定义条件。只对某个数的倍数进行操作,使用if语句。条件:7的倍数 x%7==0;
3)因为该数倍数的个数不确定,只要符合条件,就通过一个变量来记录住这个变化的次数。该变量随着7的倍数的每一次出现而自增。

 1 public static void main(String[] args)
 2     {
 3         int num=getNum(150,100,7);
 4         System.out.println(num);
 5     }
 6     //将功能封装成函数,需要传进来三个变量,分别是较小的整数,较大的整数和求倍数个数的整数。
 7     public static int getNum(int start,int end,int key)
 8     {
 9         int num=0,min,max;
10         min=(start<end)?start:end;
11         max=(min==start)?end:start;
12         for (int x=min;x<=max ;x++ )
13         {
14             //遍历过程中加入判断语句,如果符合条件,用变量通过自增记住变化
15             if (x%key==0)
16                 num++;
17         }
18         return num;
19     }
20 }

 


6.5.3 嵌套
(1)定义
语句嵌套形式:其实就是语句中还有语句。循环嵌套,就是循环中还有循环。
(2)应用:打印图形
对于打印图形来说,外循环控制的是行数,内循环控制的是每一行的列数,也就是一行中元素的个数
打印图形使用嵌套循环时不是规律的规律:
图形尖朝上:可以改变条件,让条件随着外循环变化
图形尖朝下:可以改变初始化值,让初始化值随着外循环变化
(3)代码示例
例:打印9x9乘法口诀表
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
……

思路:
1)首先将图形简化为
1
2 4
3 6 9
……
这就相当于是一个三角形了。
2)打印图形,选择嵌套循环。
3)图形尖朝上,改变条件,让条件随着外循环变化。
4)每一个表达式都是图形中的一个元素,为了图形整齐,元素之间加制表符排版。

 1 class MultiplicationTable
 2 {
 3     public static void main(String[] args)
 4     {
 5         printMulTable(9,9);
 6     }
 7     public static void printMulTable(int row,int column)
 8     {
 9         //通过外循环控制行数
10         for (int x=1;x<=row;x++ )
11         {
12             //图形尖朝上,让条件随外循环变化
13             for (int y=1;y<=x && y<=column ;y++ )
14             {
15                 //打印图形的内容
16                 System.out.print(y+"*"+x+"="+x*y+"\t");
17             }
18             System.out.println();
19         }
20     }
21 }

 

 


7.函数

7.1 函数的基本概念
(1)定义:函数就是定义在类中的具有特定功能的一段独立小程序。也称为方法。
(2)格式:
修饰符 返回值类型 函数名(参数类型 形式参数1,参数类型 形式参数2)
{
    执行语句;
    return 返回值;
}
    返回值类型:函数运行后的结果的数据类型。
    参数类型:是形式参数的数据类型。
    形式参数:是一个变量,用于存储调用函数时传递给函数的实际参数。
    实际参数:传递给形式参数的具体数值。
    return:用于结束函数。
    返回值:该值会返回给调用者。

(3)特点
定义函数可以将功能代码进行封装,便于对该功能进行复用,函数只有被调用才会被执行,它的出现提高了代码的复用性。函数中只能调用函数,不可以在函数内部定义函数。

7.2 如何定义一个函数(两个明确)
明确要定义的功能最后的运算结果是什么(明确返回值类型);
明确在定义该功能的过程中,是否需要未知内容参与运算(明确参数列表);

◆◆◆◆【7.3 函数的重载(Overload)】◆◆◆◆
(1)什么时候用重载:
当函数的功能一样,仅仅是参与运算的未知内容不同时,可以定义一个函数名以表示此功能,这样方便阅读。在调用时,虚拟机通过参数列表的不同来区分多个同名函数。
(2)重载的特点:
与返回值类型无关,只看参数列表。
(3)重载的好处:
方便于阅读,优化了程序设计。
(4)重载例题
原函数    void show(int a,char b,double c){}
判断下列函数是否和原函数构成了重载
A void show(int x,char y,double z){}
    没有,因为和原函数一样。
B int show(int a,double c,char b){}
    重载,因为参数类型不同。注意:重载和返回值类型没关系
C void show(int a,double c,char b){}
    重载,因为参数类型不同。
D boolean show(int c,char b){}
    重载,因为参数个数不同。
E void show(double c){}
    重载,因为参数个数不同。
F double show(int x,char y,double z){}
    没有,这个函数不可以和给定函数同时存在与一个类中。

8.数组

8.1 数组的基本概念
数组的定义
同一种类型数据的集合。其实数组就是一个容器。
数组的好处:
可以自动给数组中的元素从0开始编号,方便操作这些元素。
数组的格式
格式1:
    元素类型[] 数组名= new 元素类型[元素个数或数组长度];
格式2:
    元素类型[] 数组名= new 元素类型[]{元素,元素,……};
格式3:
    元素类型[] 数组名= {元素,元素,……};
new:在内存中产生一个容器实体,用来存储数据。
null:是一个常量,只有引用数据类型才能使用这个常量。数组名就是一个数组类型的数据,数组是一种单独的数据类型,数组名指向了该数组,
或叫引用了该数组。如果不想再让数组名指向该数组,数组名=null;表示不再指向该数组,而是值为空。
length:数组的一个属性,可以直接获取到数组元素个数。使用方式:数组名.length

8.2 数组的内存分配及特点

Java程序在运行时,需要在内存中分配空间。为了提高运算效率,又对空间进行了不同区域的划分,每一片区域都有特定的处理数据方式和内存
管理方式。
(1)栈内存
用于存储局部变量,数据使用完,所占空间会自动释放。凡是局部变量,都在栈内存中。
局部变量:定义在方法中的变量,方法中参数的变量,循环中的变量。
(2)堆内存
用于存放数组和对象,通过new建立的实体都存放在堆内存中。每一个实体都有内存地址值,实体中的变量都有默认初始化值,当实体不再被使用,
会在不确定的时间内启动一个垃圾回收机制将该数组实体在堆内存中清除.
(3)方法区
(4)本地方法区
(5)寄存器

8.3 数组操作常见问题

数组角标越界异常(ArrayIndexOutOfBoundsException
操作数组时,访问到了数组中的不存在的角标。
空指针异常(NullPointerException)
当引用没有指向实体(值为null),却在操作实体中的元素时。

◆◆◆【8.4 数组常见操作】◆◆◆

8.4.1 获取最值(以最大值为例)
思路:
1)获取最大值需要进行比较。每一次比较都会有一个较大的值。因为该值不确定。通过一个变量进行临时存储。
2)让数组中的每一个元素都和这个变量中的值进行比较。如果大于了变量中的值,就用该该变量记录较大值。
3)当所有的元素都比较完成,那么该变量中存储的就是数组中的最大值了。

获取最值的另一种方式。
可以将临时变量初始化为0。这种方式其实是在初始化为数组中的第一个元素的角标。

8.4.2 排序
例:对数组{2,3,5,1,6,8}进行从小到大排序
(1)选择排序
原理:
就是将数组中第一个元素分别与其它元素作比较,如果符合条件(第一个元素大于其它元素)则换位,内循环结束一次,最值(最小值)出现在头角标位置上。然后将第二个元素分别与除了第一个元素的其它元素比较,依次类推,得到最终的排序。
思路:
1)选择排序的实现方式:第一个元素分别与它后面的元素逐个比较,符合条件则换位;第二个元素分别与它后面的元素逐个比较,符合条件则换位
2)所以需要两个for循环,外循环逐一遍历数组,内循环在外循环遍历数组元素时遍历该元素后面的元素
3)元素换位也可以单独封装成一个函数来调用
4)循环结束后,数组就完成了排序

代码示例

 1 class SelectSort
 2 {
 3     public static void main(String[] args)
 4     {
 5         int[] arr={2,3,5,1,6,8};
 6         printArray(arr);
 7         selectSort(arr);
 8         printArray(arr);
 9     }
10     public static void selectSort(int[] arr)
11     {
12         //最后一个元素不用判断,所以-1可以优化一次内循环
13         for (int x=0;x<arr.length-1 ;x++ )
14         {
15             //每次都是拿一个元素和它后面的所有元素依次比较,所以y=x+1;
16             for (int y=x+1;y<arr.length ;y++ )
17             {
18                 //如果满足条件则换位
19                 if (arr[x]>arr[y])
20                 {
21                     swap(x,y);
22                 }
23             }
24         }
25     }
26     
27     private static void swap(int x,int y)
28     {
29         int temp=arr[x];
30         arr[x]=arr[y];
31         arr[y]=temp;
32     }
33     public static void printArray(int[] arr)
34     {
35         System.out.print("{");
36         for (int x=0;x<arr.length ;x++ )
37         {
38             if (x!=arr.length-1)
39                 System.out.print(arr[x]+",");
40             else
41                 System.out.println(arr[x]+"}");
42         }
43     }
44 }

 


(2)冒泡排序
原理:
对相邻的两个元素进行比较,如果符合条件(前一个元素大于后一个元素)就换位。内循环结束一次,最值(最大值)出现在末角标位置上。
思路:
1)冒泡排序的实现方式:相邻的两个元素比较,符合条件则换位;循环一次,最值出现在末角标,再将除了没有排好序的元素按同样方法比较,循环到最后一个元素。
2)定义两个for循环,外循环逐一遍历数组,内循环在外循环遍历数组过程中遍历该数组元素并进行相邻元素的比较。且外循环遍历每加1,内循环遍历就减1.
3)元素换位也可以单独封装成一个函数来调用。
4)循环结束后,数组就完成了排序。

代码示例

 1 class BubbleSort
 2 {
 3     public static void main(String[] args)
 4     {
 5         int[] arr={2,3,5,1,6,8};
 6         printArray(arr);
 7         bubbleSort(arr);
 8         printArray(arr);
 9     }
10     public static void bubbleSort(int[] arr)
11     {
12         for (int x=0;x<arr.length-1 ; x++)
13         {
14             //-x,去掉已经排好序的元素,-1,防止第一次比较时y+1角标越界
15             for (int y=0;y<arr.length-x-1 ;y++ )
16             {
17                 //每次让相邻两个元素作比较,如果符合条件就换位
18                 if (arr[y]>arr[y+1])
19                 {
20                     swap(y,y+1);
21                 }
22             }
23         }
24     }
25     private static void swap(int x,int y)
26     {
27         int temp=arr[x];
28         arr[x]=arr[y];
29         arr[y]=temp;
30     }
31     public static void printArray(int[] arr)
32     {
33         System.out.print("{");
34         for (int x=0;x<arr.length ;x++ )
35         {
36             if (x!=arr.length-1)
37                 System.out.print(arr[x]+",");
38             else
39                 System.out.println(arr[x]+"}");
40         }
41     }
42 }

 


你发现了吗?
对于选择排序和冒泡排序还可以进行优化,
问题:如果传入的数组已经是一个有序的数组了,该方法仍然会对数组进行便利。
解决办法:可以定义一个标记,判断如果在内循环遍历一遍过程中没有发生元素的换位,则说明数组排序已经完成,不需要再继续循环了。

以冒泡排序为例,优化后代码

 1     public static void bubbleSort(int[] arr)
 2     {
 3         boolean flag=false;
 4         for (int x=0;x<arr.length-1 ; x++)
 5         {
 6             //-x,去掉已经排好序的元素,-1,防止第一次比较时y+1角标越界
 7             for (int y=0;y<arr.length-x-1 ;y++ )
 8             {
 9                 //每次让相邻两个元素作比较,如果符合条件就换位
10                 if (arr[y]>arr[y+1])
11                 {
12                     swap(y,y+1);
13                     flag=true;
14                 }
15             }
16             if(flag)
17                 flag=false;
18             else
19                 break;
20         }
21     }


8.4.3 折半查找(二分查找)
折半查找可以提高效率,但是必须要保证该数组是有序的数组。

(1)普通查找,遍历数组并判断
好处:对于无序的数组同样适用
弊端:需要对数组中元素逐个判断,效率稍低

(2)折半查找
好处:提高效率。
弊端:必须要保证该数组是有序的数组。

代码示例
例:获取数组{2,4,5,7,8,19,32,45}中19第一次出现的位置

 1 class HalfSearch
 2 {
 3     public static void main(String[] args)
 4     {
 5         int[] arr={2,4,5,7,8,19,32,45};
 6         int key=getKey(arr,19);
 7         System.out.println("key="+key);        
 8     }
 9     public static int getKey(int[]arr,int key)
10     {
11         int min=0,max=arr.length-1,mid;
12         //循环条件是min小于max,当min大于max时,说明没有该元素,返回-1
13         while (min<=max)
14         {
15             //因为min和max都在判断后变化,每次都先让mid重新赋值,
16             mid=(min+max)/2;
17             if (key>arr[mid])
18                 min=mid+1;
19             else if (key<arr[mid])
20                 max=mid-1;
21             //如果通过移动后等于mid,就返回该角标
22             else
23                 return mid;
24         }
25         return -1;
26     }
27 }

 


8.5 数组中的数组:二维数组[][]

格式1:
    int[][] arr = new int[3][2];
定义了名称为arr的二维数组,二维数组中有3个一维数组,每一个一维数组中有2个元素,一维数组的名称分别为arr[0], arr[1], arr[2]。给第一个一维数组1脚标位赋值为x写法是:arr[0][1] = x;

格式2:
    int[][] arr = new int[3][];
二维数组中有3个一维数组,每个一维数组都是默认初始化值null, 可以对这个三个一维数组分别进行初始化。arr[0] = new int[3];arr[1] = new int[1]; arr[2] = new int[2];

格式3:
    int[][] arr = {{3,8,2},{2,7},{9,0,1,6}};
定义一个名称为arr的二维数组,二维数组中的有三个一维数组, 每一个一维数组中具体元素也都已初始化。第一个一维数组arr[0] ={3,8,2};第二个一维数组 arr[1] = {2,7}; 第三个一维数组 arr[2] = {9,0,1,6}; 第三个一维数组的长度表示方式:arr[2].length;

注意:
特殊写法情况:int[] x,y[]; x是一维数组,y是二维数组。

posted @ 2013-07-02 15:58  赵晨光  阅读(637)  评论(1编辑  收藏  举报
---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ------- --------------- 详细请查看:http://edu.csdn.net