各位爱好编程或者希望通过学习编程进入IT行业的同学大家好,很高兴能在这里遇见你,接下来我带你一同领略编程的魅力,以最快、最简单、最有效的方法帮助你学习Java编程。不管你之前是零基础还是负基础,都能通过我的接下来的一系列文章逐步深入。
首先我们关注一下我们的基础语法内容:
- 标识符
- 关键字
- Java 基本数据类型
- 运算符
- 表达式和语句
- 分支
- 循环
- 方法
- 变量的作用域
- 递归调用
变量:
Java 语言中,对各种变量、方法和类等要素命名时使用的字符序列称为标识符。
Java 标识符有如下命名规则:
- 标识符由字母、下划线“_” 、美元符“$”或数字组成。
- 标识符应以字母、下划线 、美元符开头。
- Java 标识符大小写敏感,长度无限制。
- 约定俗成:Java 标识符选取因注意“见名知意”且不能与 Java 语言的关键字重名。
举例说明:
|
关键字
- Java 中一些赋以特定的含义,用做专门用途的字符串称为关键字(keyword)。
- 所有Java关键字都是小写英文字符串。
- goto 和 const 虽然从未使用,但也作被为 Java 关键字保留。
Java常量
通俗简单来说呢:就是Java中保持不变的量
- Java 的常量值用字符串表示,区分不同的数据类型。
- 如整型常量 123
- 实型常量 3.14 字符常量 ‘a’ 逻辑常量 true、false
- 字符串常量 “helloworld”
- null
注意:
- 区分字符常量和字符串常量
- 区分 null 和 “”
- 常量的定义: public static final double PI = 3.14; Math.PI 端口、错误码
Java变量
给你打个比方吧,把计算机的内存好比是一个酒店,每一个变量就好比这个酒店的每一个房间,每个房间都有门牌号,就好比变量的变量名称;每个房间里面的客人就像变量里面存储的值。
- Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域。
- Java程序中每一个变量都属于特定的数据类型,在使用前必须对其声明,
- 声明格式为: type varName [=value][{,varName[=value]}] 例如:
-
public class TestVar{ public static void main(String[] args){ int i = 100; double d1, d2, d3 = 0.123; String name = "Jack"; } }
- 从本质上讲,变量其实是内存中的一小块区域,使用变量名来访问这块区域,因此,每一个变量使用前必须要先申请(声明),然后必须进行赋值(填充内容),才能使用
程序执行过程
- 聊聊程序在执行过程中的步骤,
- 首先程序是从硬盘上加载到内存里面
- 这里的内存指的是运行时内存(RAM)
JVM内存结构
1.程序计数器 PC Register
每个线程都有一个程序计算器,就是一个指针,指向方法区中的方法字节码(下一个将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不记。
2.本地方法栈 Native Method Stack
Native Method Stack中登记native方法,在Execution Engine执行时加载native libraies
本地方法栈与虚拟机栈基本类似,区别在于虚拟机栈为虚拟机执行的java方法服务,而本地方法栈则是为Native方法服务
3.方法区 Method Area
用于存储虚拟机加载的:静态变量+常量+类信息+运行时常量池 (类信息:类的版本、字段、方法、接口、构造函数等描述信息 )
默认最小值为16MB,最大值为64MB,可以通过-XX:PermSize
和 -XX:MaxPermSize
参数限制方法区的大小
4.栈 JVM Stack
编译器可知的各种基本数据类型(boolean
、byte
、char
、short
、int
、float
、long
、double
)、对象引用(引用指针,并非对象本身)
栈是java 方法执行的内存模型:
每个方法被执行的时候 都会创建一个“栈帧”用于存储局部变量表(包括参数)、操作栈、方法出口等信息。
每个方法被调用到执行完的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
(局部变量表:存放了编译器可知的各种基本数据类型(boolean
、byte
、char
、short
、int
、float
、long
、double
)、对象引用(引用指针,并非对象本身),
其中64位长度的long和double类型的数据会占用2个局部变量的空间,其余数据类型只占1个。
局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量是完全确定的,在运行期间栈帧不会改变局部变量表的大小空间)
栈的生命期是跟随线程的生命期,线程创建时创建,线程结束栈内存也就释放,是线程私有的。
5.堆 Java Heap
所有的对象实例以及数组都要在堆上分配,此内存区域的唯一目的就是存放对象实例
堆是Java 虚拟机所管理的内存中最大的一块。Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建
堆是理解Java GC机制最重要的区域,没有之一
结构:新生代(Eden区+2个Survivor区) 老年代 永久代(HotSpot有)
6.直接内存 Direct Memor
直接内存并不是JVM管理的内存,可以这样理解,直接内存,就是JVM以外的机器内存,比如,你有4G的内存,JVM占用了1G,则其余的3G就是直接内存
JDK中有一种基于通道(Channel)和缓冲区(Buffer)的内存分配方式,将由C语言实现的native函数库分配在直接内存中,用存储在JVM堆中的DirectByteBuffer来引用
由于直接内存收到本机器内存的限制,所以也可能出现OutOfMemoryError的异常。
Java变量的分类
按被声明的位置划分:
- 局部变量:方法或语句块内部定义的变量
- 成员变量:方法外部、类的内部定义的变量
注意:类外面(与类对应的大括号外面)不能有变量的声明
按所属的数据类型划分:
- 基本数据类型变量
- 引用数据类型变量
局部变量,成员变量举例:
public class TestVar{
public static String company = "NBA";
public static void main(String[] args){
String name = "curry";
System.out.println("company是成员变量:" + company);
System.out.println("name是局部变量:" + name);
}
}
变量需要先复制在运算
public void method() {
int i;
int j = i+5 ; // 编译出错,变量i还未被初始化
double d = 3.14;
}
变量按照类型来划分
Java基本数据类型:
Java中定义了4类8种基本数据类型。
- 逻辑型-boolean
- 字符型- char (2) a~z A~Z 0~9 不是字符串 单引号’’
- 数值型
- 整数型- byte(1), short(2), int(4), long(8) 默认:int long l = 23L;
- 浮点数型- float(4), double(8) 默认:double float f = 3.14f;
编码问题 Unicode 全球统一编码 1字节8位 255 -128~127
编码问题 byte 和 bit 区别
- bit 一个比特就是一个二进制数的最小单元,就像我们说我们能够拥有的最小金额的钱就是一分一样,只不过比特是在二进制数中罢了。 一个比特只能拥有一个值,不是0就是1,所以如果我给你一个值0,你可以说它就是一个比特,如果我给你两个(00),你就可以说它们是两个比特了。
- byte 1个byte就是一个字节,一个字节=8个bit
- 那么1个byte = 8个bit
- 二进制的首位:1表示负数,0表示正数
- 一个字节二进制就是:10000000 到 01111111 的区间
- 二进制10000000 == -128(十进制) & 二进制01111111 == 127(十进制)
- 因此:byte的取值范围就是 -128 到 127
代码练习:
public class TestByte{
public static void main(String[] args){
//byte number = 127;
byte number = -128;
System.out.println(number);
}
}
逻辑型Boolean
- boolean 类型适于逻辑运算,一般用于程序流程控制 。
- boolean 类型数据只允许取值 true 或 false 用法举例:
boolean flag;
flag = true;
if(flag) {
//do something
}
字符型char
- char 型数据用来表示通常意义上的“字符”
- char代表的是utf16编码单元
- 字符常量为用单引号括起来的单个字符,
- 例如: char eChar = 'a'; char cChar ='中';
注意char类型的值需要的是:引文的单引号 'A' ,而不是双引号
char类型的练习:用两种方法输出“中” 的ASCII
//练习:用两种方法输出“中” 的ASCII
public class Test{
public static void main(String args[]){
char temp1 = '4';
char temp2 = '中';
char temp3 = 's';
System.out.println(temp2+0);
System.out.println(temp1+0);
}
}
整数类型
- Java 各整数类型有固定的表数范围和字段长度,其不受具体操作系统的影响,以保证Java程序的可移植性。
- Java语言的整型常量默认为int型,声明long型常量可以后加‘ l ’或‘ L ’ ,
- 如:int i1 = 600; //正确 long l1 = 8888888888L; //必须加l否则会出错
|
浮点类型
- 与整数类型类似,Java浮点类型有固定的表数范围和字段长度,不受平台影响。
- Java 浮点类型常量有两种表示形式
- 十进制数形式,例如: 3.14 314.0 .314
- Java 浮点型常量默认为 double 型,如要声明一个常量为 float 型,则需在数字后面加 f 或 F ,
- 如: double d = 12345.6; //正确 float f = 12.3f; //必须加f否则会出错
- 下面列出 Java 的各种浮点类型
类 型 | 占用存储空间 | 表数范围 |
float | 4字节 | -3.403E38~3.403E38 |
double | 8字节 | -1.798E308~1.798E308 |
Java类型转换
- Java中可以从任意基本类型转型到另外的基本类型
- 例外---> boolean 类型不可以转换为其他的数据类型。
- 转换分为默认转换和强制转换 整形,字符型,浮点型的数据在混合运算中相互转换,转换时遵循以下原则:
- 容量小的类型默认转换为容量大的数据类型;数据类型按容量大小排序为:
- byte,short,char->int->long->float->double
- byte,short,char之间不会互相转换,他们三者在计算时首先回转换为int类型
- 容量大的数据类型转换为容量小的数据类型时,要加上强制转换符,但可能造成精度降低或溢出;使用时要格外注意。
- 有多种类型的数据混合运算时,系统首先自动的将所有数据转换成容量最大的那一种数据类型,然后再进行计算。(看下页)
- 实数常量(如:1.2)默认为 double。整数常量(如:123)默认为 int 。
多种类型的数据混合运算
有多种类型的数据混合运算时,系统首先自动的将其中容量小的数据转换成容量最大的那一种数据类型,然后再进行计算。
- 如果其中一个运算对象是double类型的 另一个也会被转换成double类型。
- 否则,如果其中一个运算对象是float类型的, 另一个也会被转换成float类型的。
- 否则,如果其中一个运算对象是long类型的, 另一个也会被转换成long类型的。
- 否则,如果其中一个运算对象是int类型的, 另一个也会被转换成int类型的。
- 否则,如果其中一个运算对象是short类型的, 另一个也会被转换成short类型的。
总而言之一句话:如果运算中出现了更大的类型,则小类型会转换为大类型计算。
变量赋值运算的问题
- 小数默认都是double类型例如:0.1
- 整数默认的类型是int类型;
- float number = 0.1; 错误
- float number = 0.1f;正确;
- 当赋值的时候,不能超过类型的最大值 int number = 1; 正确
- int number = 8888888888;错误,超过了int的最大值
- 如何接收大的数据 long number = 8888888888L;
- 如果小范围的类型和大范围类型计算之后会变为大范围类型,例如:
- ‘a’+0 这里输出的是 97 , why?
- float f4 = f1+f2*0.1; 错误 float f4 = (float)(f1+f2*0.1); 正确
纠错练习
public void method(){
int i=1,j;
float f1=0.1; float f2=123;
long l1 = 12345678,l2=8888888888;
double d1 = 2e20,d2=124;
byte b1 = 1,b2 = 2,b3 = 129;
j = j+10;
i = i/10;
i = i*0.1;
char c1='a',c2=125;
byte b = b1-b2;
char c = c1+c2-1;
float f3 = f1+f2;
float f4 = f1+f2*0.1;
double d = d1*i+j;
float f = (float)(d1*5+d2);
}
运算符
Java 语言支持如下运算符:
- 算术运算符: +,-,*,/,%,++,--
- 关系运算符: >,<,>=,<=,= =,!=
- 逻辑运算符: !,& , | , ^ , &&,||
- !-逻辑非 &- 逻辑与 | - 逻辑或 ^ - 逻辑异或 &&- 短路与 || - 短路或
- &&, ||,! 逻辑运算符只能用于boolean身上
- 位运算符: &,|,^,~ , >>,<<,>>>
- 赋值运算符: =
- 扩展赋值运算符:+=,-=,*=,/=
- 字符串连接运算符:+
代码案例:
自增自减的前后顺序
public class Test {
public static void main(String arg[]) {
int i1 = 10, i2 = 20;
int i = i2++;
System.out.print("i=" + i);
System.out.println(" i2=" + i2);
i = ++i2;
System.out.print("i=" + i);
System.out.println(" i2=" + i2);
i = --i1;
System.out.print("i=" + i);
System.out.println(" i1=" + i1);
i = i1--;
System.out.print("i=" + i);
System.out.println(" i1=" + i1);
}
}
输出:
- i=20 i2=21
- i=22 i2=22
- i=9 i1=9
- i=9 i1=8
注意: ++(--) 在前时先运算再取值。 在后时先取值再运算。
逻辑运算符
- 逻辑运算符:
- !-逻辑非 &- 逻辑与 | - 逻辑或 ^ - 逻辑异或
- &&- 短路与 || - 短路或 &&, ||,! 逻辑运算符只能用于boolean身上。
a | b | !a | a&b | a|b | a^b | a&&b | a||b |
true | true | false | true | true | false | true | true |
true | false | false | false | true | true | false | true |
false | true | true | false | true | true | false | true |
false | false | true | false | false | false | false | false |
代码案例:
public class Test{
public static void main(String args[]){
boolean a,b,c;
a = true; b = false;
c = a & b; System.out.println(c);
c = a | b; System.out.println(c);
c = a ^ b; System.out.println(c);
c = !a; System.out.println(c);
c = a && b;System.out.println(c);
c = a || b; System.out.println(c);
}
}
短路与具有短路作用,代码案例如下
public class Test{
public static void main(String args[]) {
int i=1,j=2;
boolean flag1 = (i>3)&&((i+j)>5);
//第二个操作数将不再计算
boolean flag2 = (i<2)||((i+j)<6);
//第二个操作数将不再计算
}
}
赋值运算符与扩展赋值运算符
- 赋值运算符 (=)
- 当“=”两侧数据类型不一致时,可以适用默认类型转换或使用强制类型转换原则进行处理
- long l = 100; int i = (int)l;
- 注意:可以将整型常量直接赋值给byte, short, char等类型变量,而不需要进行强制类型转换,只要不超出其表数范围
- byte b = 12; char c = 100;
- X byte bb = 256; X short s = -32769;
- 当“=”两侧数据类型不一致时,可以适用默认类型转换或使用强制类型转换原则进行处理
- 扩展赋值运算符
运算符 | 用法举例 | 等效的表达式 |
+= | a += b | a = a+b |
-= | a -= b | a = a-b |
*= | a *= b | a = a*b |
/= | a /= b | a = a/b |
%= | a %= b | a = a%b |
字符串连接符
- “+” 除用于算术加法运算外,还可用于对字符串进行连接操作
- int id = 800 + 90;
- String s = "hello" + "world";
- “+”运算符两侧的操作数中只要有一个是字符串(String)类型,系统会自动将另一个操作数转换为字符串然后再进行连接。
- int c = 12;
- System.out.println("c=" + c);
表达式
- 表达式是符合一定语法规则的运算符和操作数的序列
- a
- 5.0 + a
- (a-b)*c-4
- i<30 && i%10!=0
- 表达式的类型和值
- 对表达式中操作数进行运算得到的结果 称为表达式的值。
- 表达式值的数据类型即为表达式的类型 。
- 表达式的运算顺序
- 应按照运算符的优先级从高到低的顺序进行。
- 优先级相同的运算符按照事先约定的结合方向进行。
R to L | . ( ) { } ; ,++ -- ~ ! (data type) |
L to R | * / % |
L to R | + - |
L to R | << >> >>> |
L to R | < > <= >= instanceof |
L to R | == != |
L to R | & |
L to R | ^ |
L to R | | |
L to R | && |
L to R | || |
R to L | ? : |
R to L | = *= /= %= += -= <<= >>= >>>= &= ^= |= |
以上表中,从上到小,从做到右,优先级是:由高到低。
代码练习:
- char c = (char)(Math.random()*26+’a’);
- Math.random()返回一个double值
- 所以26被转成double进行乘法运算,乘积是个double
- 为了完成加法,a必须被转成double
- 最后获得的double再转成char
- 如果从29.7转成char,是30还是29?
- Math.random()输出0-1之间的数。[0,1)
Scanner扫描器:
Scanner类:扫描器,是JDK中一个常用的工具类,来自于java.util包中,主要用来接收用户输入的信息。
代码案例:
import java.util.Scanner;
public class TestScanner{
public static void main(String[] args){
System.out.print("您好,请输入您的名字:");
Scanner sc = new Scanner(System.in);
String name = sc.next();
System.out.print(name+",欢迎你进入java世界");
}
}
代码练习:
做练习:
- 电脑输入自己的:名字,性别,出生年,身高,体重。
- 返回电脑自动返回:
- 库里
- 男
- 1988年出生,今年27
- 身高:191.1cm
- 体重:83.9kg
- 男性:身高(厘米)-105= 标准体重(千克),
- 女性:身高(厘米)-100= 标准体重(千克)
未完待续,请关注下一篇文章~