频道栏目
首页 > 资讯 > Java > 正文

java基础知识学习笔记(二)

16-03-31        来源:[db:作者]  
收藏   我要投稿

java基本的程序设计结构

1 一个简单的java例子

public class FirstExample{
    public static void main(String[] args){
        System.out.println("we will not use 'hello world' ");
    }
}

从这个程序中,我们可以知道哪些?
1 java对大小写很敏感,main写成Main,程序无法执行
2 public访问修饰符,控制程序的其他部分对这段代码的访问级别
3 class表名java程序包含在类中,这里,只需要将类作为一个加载程序逻
辑的容器,程序逻辑定义了应用程序的行为。
4 class后面跟的是类名,命名规则:类名是以大写字母开头的名词。如果
名字由多个单词组成,每个单词的第一个字母都应该大写。其他等同于标
识符的命名规则。
5 文件名与公有类的类名一致,如FirstExample.java
6 每个java应用程序必须有一个main方法
7 {}方法体开始和结束。每个句子必须用‘;’结束,回车不是结束的标志,因此,可以将一条java语句写在多行上
8 System.out.println(),方法调用
9 “”引用字符串
10 方法可以没有参数,也可以有多个参数,但必须用()表示例如,不带
参数的println方法只打印一个空行。使用下面的语句:

System.out.println()
Note:
运行编译程序时, Java虚拟机将从指定类中的main方法开始执行(这里的“方法”就是Java中所说的“函数”),
因此为了代码能够执行,在类的源文件中必须包含一个main方法。当然,也可以将用户自定义的方法添加到类中,
并且在main方法中调用它们。

根据Java语言规范, main方法必须声明为public

Java的类与C++的类很相似,但还是有些差异会使人感到困惑。
例如, Java中的所有函数都属于某个类的方法(标准术语将其称为方法,而不是成员函数)。
因此, Java中的main方法必须有一个外壳类。读者有可能对C++中的静态成员函数( static member functions)十分熟悉。
这些成员函数定义在类的内部,并且不对对象进行操作。 Java中的main方法必须是静态的。
最后,C/C++一样,关键字void表示这个方法没有返回值,所不同的是main方法没有给操作系统返回“退出代码”。
如果main方法正常退出,那么Java应用程序的退出代码为0,表示成功地运行了程序。
如果希望在终止程序时返回其他的代码,那就需要调用System.exit方法。

2 注释

与多数设计语言一样,java中的注释不会出现在可执行程序中。
注释类型:
单行://注释的内容
多行:/*注释的内容 */
另一种:/**注释的内容*/

Note:
在Java中, /* */注释不能嵌套。也就是说,如果代码本身包含了一个*/,就不能用/*和*/将注释括起来。

3 数据类型

四种整型,两种浮点,一种char,一种Boolean
1 整型

类型 存储要求 取值范围
int 4字节 -2 147 483 648~2 147 483 647(正好超过20亿)
short 2字节 -32 768~32 767
long 8字节 -9 223 372 036 854 775 808~9 223 372 036 854 775 807
byte 1字节 -128~127
在java中,整型的取值范围固定,与平台无关,这就解决了移植性的问题,而c/c++需要针对不同的处理器选择最为有效的整型,会导致整数溢出问题

2 浮点型

类型 存储要求 取值范围
float 4字节 大约±3.402 823 47E+38F(有效位数为6~7位)
double 8字节 大约±1.797 693 134 862 315 70E+308(有效位数为15位)
常量Double.POSITIVE_INFINITY、 Double.NEGATIVE_INFINITY和Double.NaN(与相应的Float类型的常量一样),例如:
一个正整数除以0的结果为正无穷大。计算0/0或者负数的平方根结果为NaN。

检测一个数是不是NaN,不能
if(x==Double.NaN)
//所有"非数值"的值都认为是不相同的。可以用Double.NaN(x)
if(Double.NaN(x))

3 char类型
记住以下几点:
1 ‘A’和“A”不同:前者是字符常量65,后者是包含字符A的字符串
2 在”和”“中可以假如转义字符,但只有\u可以不在内部,如\u005B和\u005D是(和)的编码。
3 java中采用的UTF-16描述一个代码单元
4 强烈建议不要在程序中使用char类型

4 boolean型

在C++中,数值或指针可以代替boolean值。整数0相当于布尔值false,非0值相当于布尔值true。在Java中则不行。
因此, Java应用程序员不会遇到下述麻烦:
if(x=0)//
在C++中这个测试可以编译运行,其结果总是false。而在Java中,这个测试将不
能通过编译,其原因是整数表达式x = 0不能转换为布尔值。

4 变量

记住一下几点:
1 变量名区分大小写
2 在c/c++,区分变量定义和声明,如:
int i=10;//定义变量
extern int i;//声明一个变量
java中不做区分,可以直接写成:int i=10;//声明,定义,初始化

3 与变量对应的就是常量,用final声明,通常常量名使用大写,常量不能更改,如:
final int PI=3.14;

4 希望某个常量可以在一个类中的多个方法中使用,通常将这些常量称为类
常量。可以使用关键字static final设置一个类常量。需要注意,类常量的定义位于main方法的外部。

 const是Java保留的关键字,但目前并没有使用。在Java中,必须使用final定义常量。

5 运算符

关于运算符需要注意的一些问题:
1 整数除0会产生一个异常,浮点数除0则会得到无穷或NaN
2 自增运算符与自减运算符,举个例子:

int m=7;
int n=7;
int a=2*++m;//m=8,a=16
int b=2*n++;//n=8,b=14

3 关系运算符与boolean运算符,举个例子:

if(x!=0&&1/x>x+y)
当x为0时,不会计算第二部分。因此,若x为0, 1/x不被计算,也不会出现除以0的错误。&&和 || 是按照“短路”方式求值的。

4 位运算符(这个用的较少,但容易忽略)

&( "与")、 |( "或")、 ^( "异或")、 ~( "非")
“ >>”和“ <<”运算符将二进制位进行右移或左移操作
>>>运算符将用0填充高位; >>运算符用符号位填充高位。没有<<<运算符

对移位运算符右侧的参数需要进行模32的运算(除非左边的操作数是long类型,在这种情况下需对右侧操作数模64)。例如, 1 << 35与1 << 3或8是相同的。

5 数学函数和常量
举个例子:

double x=4;
double y=Math.sqrt(x);
System.out.println(y);//print 2.0
Note:
println方法和sqrt方法存在微小的差异。 println方法操作一个定义在System类中的System.out对象。但是, Math类中的sqrt方法操作的不是对象,这样的方法被称为静态方法。

提示:从JDK 5.0开始,不必在数学方法名和常量名前添加前缀“ Math.”,而只要在源文件的顶部加上下列内容就可以了。
例如:
import static java.lang.Math.*;

6 数值之间的转换规则
贴个图,不解释
这里写图片描述
实心箭头,表示无信息丢失的转换;虚箭头,表示可能有精度损失的转换。
例如:123 456 789是一个大整数,它所包含的位数比float类型所能够表达的位数多。当将这个整型数值转换为float类型时,将会得到同样大小的结果,但却失去了一定的精度。
int n=123456789;
float f=n;//f is 1.234567892 E8

当使用数值进行二元运算时,先将两个操作数转换为同一类型,转换规则如下:
如果两个操作数中有一个是double类型的,另一个操作数就会转换为double类型。
否则,如果其中一个操作数是float类型,另一个操作数将会转换为float类型。
否则,如果其中一个操作数是long类型,另一个操作数将会转换为long类型。
否则,两个操作数都将被转换为int类型。

强制转换,举个例子;

double x=9.997;
int n=(int)x;//n is 9

如果取最接近的整数,可以使用:

double x=9.997;
int n=(int)Math.round(x);//n is 10

不要在boolean类型与任何数值类型之间进行强制类型转换,如果转换可以使用条件表达式b? 1:0。

7 括号与运算符级别
如果不使用圆括号,就按照给出的运算符优先级次序进行计算。同一个级别的运算符按照从左到右的次序进行计算(除了表中给出的右结合运算符外。)

运算符 结合性
[ ] . ( ) (方法调用) 从左向右
! ~ ++ – + (一元运算) - (一元运算) ( ) (强制类型转换) new 从右向左
*/ % 从左向右
加 - 从左向右
<< >> >>> 从左向右
< <= > >= instanceof 从左向右
== != 从左向右
& 从左向右
^ 从左向右
按位或 从左向右
&& 从左向右
从左向右
?: 从右向左
= += -= *= /= %= &= 或= ^= <<= >>= >>>= 从右向左

8 枚举类型
这里先不做解释

6 字符串

从概念上讲,java字符串就是Unicode字符序列。如,串“ Java\u2122”由5个Unicode字符J、 a、 v、 a和TM。java没有内置的字符串类型(基本数据来了类型里没有),在java标准类库里提供了一个预定义的String类。每个“”括起来的都是字符串的一个实例:

String string="";//an empty string
String String="hello";//String是Java的一个类,类名是标识符,所以String可以做标识符。
String sizeof="sizeof";//There is no sizeof operator.Java中没有sizeof运算符,所以sizeof可以作为标识符

1 子串
举个例子:

String greeting="hello";
String s=greeting.subString(0,3);//s is hel

解释一下subString函数:
第一个参数,从0位置开始;第二个参数,到3结束(0,1,2,不包括3)。
则求子串的长度就比较简单,即3-0=3。
2 拼接
所谓拼接,即用+连接两个字符串。举个例子:

String a="hello";
String b="world";
int age=13;
String c=a+b;//c is helloworld
String d=a+age;//d is hello13

两个原则:
1 单词之间没有空格, +号按照给定的次序将两个字符串拼接起来
2 当将一个字符串与一个非字符串的值进行拼接时,后者被转换成字符串

3 不可变字符串
String类没有提供修改字符串的方法,如果希望将greeting的内容修改为“ Help!”,不能直接地将greeting的最后两个位置的字符修改为‘ p’和‘ !’。在c中实现起来,就比较麻烦:

在这里写提一下,将字符串认为是字符型数组:
char greeting[]="hello";
这种认识是错误的, Java字符串更加像char*指针,
char *greeting="hello";
当采用另一个字符串替换greeting的时候, c代码主要进行下列操作:
char *temp=malloc(6);
strncpy(temp,greeting,3);
strncpy(temp+3,"p!",3);
greeting=temp;

在Java中实现这项操作非常容易。首先提取需要的字符,然后再拼接上替换的字符串:

greeting=greeting.subString(0,3)+"p!";//greeting is help!

在java的源码文档中,将String类对象成为不可变字符串,在这里会有一个疑问:

String greeting="hello";
greeting="help!";

以上代码只是修改了greeting引用的地址,即原来引用的是“hello”,后来引用“help!”,那原来的“hello”去哪了?

这样做会不会产生内存遗漏呢?毕竟,原始字符串放置在堆中。十分幸运, Java将自动地进行垃圾回收。如果一块内存不再使用了,系统最终会将其回收。

当然,C++ string对象也自动地进行内存的分配与回收。内存管理是通过构造器、赋值操作和析构器显式执行的。然而, C++字符串是可修改的,也就是说,可以修改字符串中的单个字符。

为什么这么设计?看起来好像修改一个代码单元要比创建一个新字符串更加简洁,效率更高?

答案是:也对,也不对。的确,通过拼接“ Hel”和“ p!”来创建一个新字符串的效率确实不高。但是,不可变字符串却有一个优点:编译器可以让字符串共享。

为了弄清具体的工作方式,可以想像将各种字符串存放在公共的存储池中。字符串变量指向存储池中相应的位置。如果复制一个字符串变量,原始字符串与复制的字符串共享相同的字符。

总而言之, Java的设计者认为共享带来的高效率远远胜过于提取、拼接字符串所带来的低效率。查看一下程序会发现:很少需要修改字符串,而是往往需要对字符串进行比较。

4 检查字符串是否相等
如果你认为比较是否相等,可以用“==”即可,那你就错了,举个例子:

String greeting="hello";//initialize greeting to a string
if(greeting="hello")...
//probably true
if(greeting.subString(0,3)=="hel")...
//probably false
why?

如果虚拟机始终将相同的字符串共享,就可以使用 == 运算符检测是否相等。但实际上只有字符串常量是共享的,而+或substring等操作产生的结果并不是共享的。因此,千万不要使用 == 运算符测试字符串的相等性,以免在程序中出现糟糕的bug。从表面上看,这种bug很像随机产生的间歇性错误。

那在java中怎么比较字符串是否相等?

String greeting=hello;
"hello".equals(greeting)...//true
"Hello".equalsIgnore(greeting)...//true,不区分大小写,
Note:
对于习惯使用C++的string类的人来说,在进行相等性检测的时候一定要特别
小心。 
C++的string类重载了==运算符以便检测字符串内容的相等性。可惜Java没有采用这种方式,
它的字符串“看起来、感觉起来”与数值一样,但进行相等性测试时,其操作方式又类似于指针。
语言的设计者本应该像对+那样也进行特殊处理,即重定义 == 运算符。
当然,每一种语言都会存在一些不太一致的地方。C程序员从不使用 == 对字符串进行比较,而使用strcmp函数。 
Java的compareTo方法与strcmp完全类似,因此,可以这样使用:
if(greeting.comepareTo("hello")==0)...
不过,使用equals看起来更为清晰。

5 代码点与代码单元
什么是代码点和代码单元?
Java中,char[]、String、StringBuilder和StringBuffer类中采用了UTF-16编码,使用U+0000~U+FFFF来表示一个基本字符(BMP字符),但是位于U+D800到U+DBFF和U+DC00到U+DFFF的char被视为无定义字符。大多数的常用Unicode字符使用一个代码单元就可以表示,而辅助字符需要一对代码单元表示。即:基本字符用一个char表示,辅助字符使用一对char表示。

Java使用代码点(Unicode code pointer)这个概念来表示范围在U+0000与U+10FFFF之间的字符值(int型),代码单元(Unicode code unit)表示作为UTF-16编码的代码单元的 16位char值(char型)。也就是说,可能存在一个字符,它的代码点数量是1,而代码单元数量是2。所以,代码单元的数量并不一定是字符的数量。

相比之下,代码单元更加偏底层。

相关函数:
length()函数返回采用UTF-16编码标识的给定字符串所需要的代码单元的数量。
codePointCount()函数返回采用UTF-16编码标识的给定字符串所需要的代码点的数量。

测试程序:


package com.xujin;

public class Test{
    public static void main(String...args){     
        char[] ch = Character.toChars(0x10400);
        System.out.printf("U+10400 高代理字符: %04x\n", (int)ch[0]);//d801
        System.out.printf("U+10400 低代理字符: %04x\n", (int)ch[1]);//dc00   
        String str = new String(ch);
        System.out.println("代码单元长度: " + str.length());//2
        System.out.println("代码点数量: " + str.codePointCount(0, str.length()));//1
        System.out.println(str.codePointAt(0));//返回给定位置开始或结束的代码点,66560
        System.out.println(str.charAt(1));//返回给定位置的代码单元,由于未定义,返回?

        //遍历一个字符串,打印出所有字符的代码点
        str += "Hello,world!";
        int i = 0;
        int cp = str.codePointAt(i);
        while(i < str.length()){
            System.out.println(str.codePointAt(i));
            if(Character.isSupplementaryCodePoint(cp))
                i += 2;//如果cp所在的位置是代码点的第一部分,执行此处
            else i++;
        }
        /*
         * 66560 
         * 72 
         * 108 
         * 111 
         * 119 
         * 114 
         * 100
         */
    }
}

java字符串是由char序列组成,char是一个采用UTF-16编码表示
Unicode代码点的代码单元。常用Unicode字符使用一个代码单元就可以表示,而辅助字符需要一对代码单元表示。

length方法将返回采用UTF-16编码表示的给定字符串所需要的代码单元数量。例如:

String greeting="hello";
int l=greeting.length();//5

要想得到实际的长度,即代码点数量,可以调用:

int cpCount = greeting.codePointCount(0, greeting.length() );
//为什么说这个是实际长度?

调用s.charAt(n) 将返回位置n的代码单元, n介于0~s.length()-1之间。例如:

char first=greeting.charAt(0);//first is h
char last=greeting.charAt(4);//last is o
//返回字符

//要想得到第 i 个代码点,应该使用下列语句
int index = greeting.offsetByCodePoints(0, i);
int cp = greeting.codePointAt(index);
//返回ascii值

6 字符串API

7 输入输出

8 控制流程

9 大数值

10 数组

相关TAG标签
上一篇:[从头学数学] 第155节 圆 小结与复习题解读
下一篇:浅谈三种解密 HTTPS 流量的方法
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站