前言:大学专业学的是化学,但是对化学不感兴趣,错过了转专业的机会。然而又想在热门的IT行业分一杯羹,没办法只能靠自己吭哧吭哧地学了。去年自学了两个月C语言,看视频,刷题,过了计算机二级。稍微有点基础,给我一串代码能看懂,但也仅仅停留在看懂。C语言是过程化语言,学起来抽象、吃力,门槛太高,所以选择Java系统地浅显地研究一下。
以前做的笔记都是写在草稿纸上的,一不小心弄没了就没法复习。索性就拿blog当笔记吧。这篇我会系统地整理一下相关知识,有些实例及项目就放在其他文章里吧。如果有人发现bug连篇,还希望多多指教。
1. 基础知识
1.1 Java简介
1.1.1 什么是java语言
java是1995年sun公司推出的面向对象编程语言,在C++的基础上摒弃了多线程、指针等难理解的部分,最初名字是OAK,后来重新命名为java(因为OAK已经被注册了)
1.1.2 java代码编译运行的过程
.java是源代码文件
.class 是编译后的字节码文件
1.1.3Java的版本
-
JavaSE
Java的标准版,主要用于桌面应用程序的开发 -
JavaEE
Java的企业版,主要用于企业级分布式网络程序的开发 -
JavaME
用于嵌入式开发,pad、手机、电子设备等
1.2 开发工具
1.2.1我用的是Eclipse,环境配置网上教程很多,此处就不赘述了。
1.2.2Eclipse介绍
IBM公司开发的集成开发工具,开源的。
1.3 编程规范
1.3.1 代码缩进
- 代码缩进统一4个字符,遇到分支时就按Tab键,直观清晰。
1.3.2 常量、变量命名规范
- 常量一般全部大写 如:
PAI
- 变量
-成员变量:以m_
开头
-普通变量:与实际意义相关,如:Student1
1.3.3 方法的命名
- 首字母大写,后面大小写混合,如:
int AddTwoNum(){ int num1,int num2}
1.3.4 关键字
- 关键字不能充当标识符
所谓的标识符,就是常量、变量、方法、数组等的命名
1.4 数据类型
1.4.1 基本数据类型
-
逻辑类型(布尔型)
- 常量:true、false
- 变量:用关键字boolean声明,可以赋初值
boolean male = true,on = true,off = false;
-
整数类型
-
int型(占4字节,32位,^31 ~ 2^31-1)
常量:十进制(123)、八进制(017)、十六进制(0x2ABC,不区分大小写)
变量:用关键字int声明,可以赋初值
java int a = 2019,y = 5,z;
-
short型(2字节,16位,范围-2^15 ~ 2^15-1)
常量:没有short类型常量,但可以强制转化
变量:同int型 -
long型(8字节,64位,范围-2^63 ~ 2^63-1)
常量:long类型后常用L修饰,如:123L、017L、0xABCL -
byte型(1字节,8位,范围-2^7 ~ ~ 2^7-1)
常量:没有byte类型,但可以强制转化
变量:同int型> 注意:Java没有无符号整形变量,区别于C语言
-
字符类型(2字节,16位,无负号,范围0 ~ 2^16-1)
常量:用英文输入法的单引号扩起的Unicode表中的一个字符
变量:用关键字char声明char a = 'c',hone = '家'
-
浮点类型
-
单精度浮点型 float (4字节,32位,范围1.4E-45 ~ 3.4028235E38)
常量:123.456f、123.456F、1e-12F
变量:关键字float声明赋值时,若数字超过8位,则从左往右存储8位;
数字后面必须有数字f或F。
123.456789 >> 123.45678ffloat a = 123.456f,b = 123.45F;
-
双精度浮点型(8字节,64位,范围 4.9E-324 ~ 1.7976931348623157E308
和- 1.7976931348623157E308 ~ -4.9E-324 )
常量:123.456d、0.05、1e-90
变量:关键字double 声明
-
存储时保留16位有效数字;
后缀d或D可以省略。
1.4.2数据类型转换
-
隐式类型转换
八种基本数据类型可以混合运算,两种不同类型的数据运算时会先自动转换成同一种,再进行运算。
按精度从低到高排序:byte、short、char、int、long、float、double
不包含boolean当低级别的变量赋值给高级别时,低级别变量会自动转换为高级别,如:
int a = 10; double b; b = a;//a的值赋给b 此时输出b的话,会显示10.0 同样 int a; char b = 'A'; a = b; 输出显示为 65(A的ASCII码值为65)
-
显式类型转换
如果说上面的隐式转换是自动的,将低级别转换为高级别,那显式转换就是 人为地将高级别转换为低级别,格式如下(类型名)要转换的数值
int x = (int )3.14; 输出 x 为 3 若直接把double型赋给int就会报错 int = 3.14;
1.4.3 引用数据类型
引用数据类型比较抽象,涉及到“对象”的知识,下面再讲。
引用数据类型包括 数组、String类型(字符串)
这有一个链接:
基本数据类型和引用数据类型的区别
1.5 数组
前面的基本类型只能声明出一个变量,假入同时要10个变量怎么办?
这时就用到了数组
1.5.1 数组的声明
- 一维数组格式:
数组元素类型 数组名[ ];
数组元素类型 [ ]数组名;
int a [];
int [] b;
- 二维数组:
int a [][];
int[][] a;
比如:a[3][6] 可以理解为,3个一维数组中每个都有6个元素。
可以一次声明多个数组
int a[],b[];
但注意 int [ ] a,b[ ]; 表示
int a[],b[][];
1.5.2 创建数组
格式:
数组名 = new 数组元素类型[ 元素个数 ];
int boy [];
boy = new boy[5];//含有五个元素的数组
也可以声明的同时创建:
int boy[] = new boy[5];
1.5.3 数组的初始化
创建数组后,系统会给每个元素一个默认值,如float类型的就是0.0。
声明的同时可以初始化
int a[]={1,2,3,4,5};
等价于
int a [] =new a[5]; a[0]=1;a[2]=2;a[3]=3;a[4]=4;a[5]=5;
1.5.4数组的存储
数组是引用类型变量,数组名就是一个引用,相当于指针,指向存放数组元素的地址。(涉及到堆和栈的概念,后面再说)
int a[] = {1,2,3}; System.out.println(a);
打印出来的结果是: [I@7f63425a
即存放数组的地址
2.运算符、表达式和语句
2.1 运算符
2.1.1 算术运算符
-
加、减(+ 、-)
- 结合性从左到右
-
乘、除、求余 (* 、/ 、%)
-
符号两边是整型或浮点型数据
-
%就是除完后的余数,结合性从左到右
-
int a = 10;
int b = 4;
int c = a%b;
c的结果为2
2.1.2 自增、自减运算符
- ++ 、- -
++X(- -X),表示在使用X前,X的值先增加(减小)1
X++(X- -),表示在使用X后,X的值增加(减小)1
例如:int a=1; int b = ++a; int c = a--; 这里a的值先加1,变成2,然后赋值给b,所以b=2 之后a又赋值给c,c=2,然后a自减1,所以a=1
2.1.3 关系运算符
- 关系运算符有 > 、< 、>= 、 <= 、 ==(等于) 、 != (不等于)
运算结果是boolean类型
1<2; 1!=3;
第一个结果为flase
第二个结果为true
2.1.4 赋值运算符
- =
- 等号左边必须是变量,不能是常量或者表达式
2.1.5 位运算符
变量在计算机内部存在形式是二进制,比如一个int型变量占4字节,就是32位
用 00000000 00000000 00000000 00000000表示,左边最高位表示符号位,0代表正,1代表负
- 按位与 &
规则是,如果参与运算的两个数据的对应为都是1,则结果的位也为1,否则为0.
比如
a: 01010100
b: 10110101
a & b: 00010100
- 按位或 |
规则是,如果参与运算的两个数据的对应为都是0,则结果的位也为0,否则为1
用上面的a b
a | b: 11110101
- 按位非 ~
是单目运算,只有一个数据。规则是,如果是0,则为1,如果是1,则为0
a:10101001
~a: 01010110
- 按位异或 ^
对应位,相同为0,不同为1
a: 10101010
b: 10110011
a ^ b : 00011001
2.1.6 instanceof运算符
二目运算符,左边是一个对象,右边是一个类,当对象是右边的类或者派生类创建的对象时,该运算的结果为true,否则是false
(涉及到类与对象的概念,后续章节会说到)
2.1.7 运算符小结
2.2 表达式
所谓表达式,就是运用运算符的语句
就像(a+b)*c 、 y = c++ 、 (x+y)>9之类的
2.3语句
2.3.1语句概述
java的语句分为6种:
- 方法调用语句
如:System.out.println("Hello World!");
- 表达式语句
如:x = 10;
- 复合语句
用{ }括起来
{x = 10;System.out.println("Hello World!"); }
- 空语句
一个分号就是一个空语句:;
- 控制语句
条件、循环 - package和import语句
与类、对象有关,后文会提到
2.3.2 条件语句
- if 语句
判断一个条件,然后执行。
格式:if(表达式){语句}
if (a==1) {a++}
//如果a等于1,那么a自增1
- if else语句
判断一个条件,如果符合,则执行,不符合,则执行else下的。
格式:
if(表达式1){语句1}
else{语句2}
if(a==1){ a++; }else{ a--;}
//如果a等于1,则a自增1;否则a自减1
- if-esle if-else
根据多个条件来判断,如果第一个条件是false,就判断第二个,第二个也是false就判断第三个,直到第N个条件符合;若都不符合,则执行else后的语句。
if(a==1){ a++;} else if(a==2){ a--;} . . . else if (a==n){ a=a+n;} else {System.out.println("都不符合");}```
- switch-case
是单条件多分支开关语句
switch后的表达式可以是byte、short、int、long类型,case后面也是这四种类型,但不能重复。
switch首先计算表达式的值,然后从case后面找对应的值,如果一致,则执行后面的语句,直到遇见break。如果没有break,那么执行完该语句后会继续执行下一个case的内容。如果case后都没有对应的值,那么将执行default后的语句
switch (number){ case 10:System.out.println("特等奖");break; case 9: System.out.println("一等奖");break; case 8:System.out.println("二等奖");break; default:System.out.println("参与奖");
2.3.3 循环语句
-
for循环
格式:for( 表达式1;表达式2;表达式3) { 若干语句 }
先执行表达式1,然后判断表达式2,若true,则执行表达式3;再判断表达式2,如此循环,直到遇到false,就退出循环。
ps:一般用于已知循环次数 -
while循环
格式:while(表达式){循环体} -
do-while循环
格式:do { 循环体 }while(表达式);
这里最后要加分号。
2.3.4 break和continue语句
- break
某次循环中用了break,那么整个循环就结束。 - continue
某次循环中用了continue,将不再执行continue后面的语句,直接跳到下一次循环
注意:如果是在嵌套循环里,break只会在一层循环里终止,不会跳出整个循环
3.类与对象
3.1类
类就是抽象出一类事物共有的属性和行为,并用语法描述出这些属性和行为。
3.1.1 类的声明
class 类名 {
}
3.1.2 类体
类体就是类声明之后的大括号,及大括号间的内容
一个类由变量和方法构成
3.1.3 成员变量
成员变量在类中声明,可以是java中任何一种数据类型,基本数据类型(布尔型、整型、字符型、浮点型);引用类型(数组、对象、接口)
位置在类体中、方法外。
例子:
class Peaple{
int age;
boolean married;
}
成员变量的使用范围:在整个类中都有效
3.1.4 局部变量
局部变量是方法里的变量,在方法被执行时创建,方法执行结束时销毁。
局部变量在使用时必须赋初值或初始化,否则会编译错误。
3.1.5 成员方法
方法对应着类的行为,定义 方法 的格式:
权限修饰符 返回值类型 方法名(参数类型 参数名){方法体 return 返回值}
class People{
public viod Eat(){
System.out.println("我会吃东西。");
}
}
3.1.5 构造方法
构造方法是类中的特殊方法
要求:
- 构造方法的名称必须和类一致。
- 可以有多个构造方法,但构造方法的签名不能一样(签名:方法名和参数列表)。
- 构造方法没有返回值。
class People{
int age;
double Height;
People(int x){
age = x;
}
People(){
age = 21;
Height = 170.0;
}
}
如果没有构造方法,系统将自动构造一个无参、无方法体的方法
People(){}
3.2 对象
对象可以理解为一类事物的实例,通过这个实例解决问题
3.2.1 对象的创建
创建对象的过程包括声明对象,以及为声明的对象分配变量
-
声明对象格式:
类名 对象名People zhangsan;
-
为声明的对象分配变量
使用new运算符和类的构造方法为声明的对象分配变量,即创建了对象。
格式:
对象名 = new 类名();zhangsan = new People();//java提供默认构造方法。若类中有构造方法,则按构造方法的格式new对象,否则创建对象就是非法的。
-
创建对象时内存的变化
声明对象时,该对象是一个空对象,内存中没有任何东西。当使用new运算符后,系统会给类的各个成员变量分配内存,然后执行构造方法中的语句。若成员变量声明时没有赋初值,则为默认值。
内存分配完毕后,系统将计算出一个叫“引用”的值,这个值包含成员变量位置及相关重要信息表达式
new People()
就是一个指向内存地址的值,同时把它赋值给对象zhangsan
接着类中成员变量的内存单元将由
zhangsan
操作管理
一个类可以创建多个对象,每创建一次对象,系统就会为成员变量分配一次内存。对象的引用存放在栈(stack)中,对象的实体,也就是分配好的变量存放在堆(heap)中
3.2.2 对象的使用
- 访问自己的变量
- 调用创建它的类中的方法
3.2.3 对象的引用和实体
类所声明的变量叫对象,对象负责存放引用,通过引用,对象可以操控分配给改对象的变量以及调用类中的方法。分配给对象的变量习惯地称作对象的实体。
-
空对象
没有实体的对象叫空对象,不能让空对象去调用方法。假如使用了空对象,编译会报空指针异常(NullPointerException) -
重要结论
如果一个类声明了两个对象obj1和obj2,两个对象的实体都一样,如果将obj1赋值给obj2obj2 = obj1 ;
那么obj2将变成obj1的引用,跟obj1完全一样。 -
垃圾回收
当obj1
和obj2
变成相同的引用时,java垃圾回收机制将取消分配给obj2
的变量,obj2
所使用的变量将会是obj1
的
举个例子:
class Test {
int x;
int y;
Test(int x,int y){
this.x = x;
this.y = y;
}
}
public static void main(String arg[]){
Test obj1 = new Test(1,2);
Test obj2 = new Test(3,4);
obj2 = obj1;//obj2的变量被释放了
System.out.println(obj2.x);
}
此时,这里输出的会是 1 ,而不是 3
3.3 类与程序的基本结构
一个java 应用程序,由若干个类组成,这些类可以在一个源文件中,也可以在多个源文件中。
应用程序中只有一个主类,该类包含着main方法,这是程序的入口。
每一个源文件都是独立的编译单位,可以在不同的程序中使用,有利于系统的维护,这也是Java复用性好的体现
3.4 参数传值
3.4.1 传值机制
一个类创建了一个对象,该对象调用类中的方法,并向方法中的参数传值时,传递过来的值是‘传值变量’的复制,所以当方法中的变量改变时,不会改变原变量的值。
3.4.2 基本数据类型的参数传值
传值的等级只能由低级向高级,比如:不能把float
型传递给int型,但可以把float
型传递给double
型
3.4.3 引用类型参数的传值
当引用型参数传值时,传递的时“引用”,也就是地址,而不会传递实体
3.5 对象的组合与复用
类中允许任何数据类型作为成员变量,所以可以将对象当作成员变量,此时创建对象时,对象中就会有其他对象。
比如:有两个类,类A和类B。类B中有个成员是类A的对象a,当类B创建对象b时,a会作为空对象存在,此时对象b就可以委托对象a调用类A的方法,即对象b通过组合的方式复用对象a的方法。
3.5.1类的关联关系
如果A类的成员变量是B类的对象,则称A类的对象关联了B类的对象。
UML图用实线表示
3.5.2 类的依赖关系
如果类A的方法中的参数或返回类型是类B声明的对象,则称A以来于B
UML图用虚线表示
3.6 实例成员和类成员
3.6.1 实例变量与静态变量
类中有成员变量和方法,而成员变量又分为实例变量和静态变量(也叫类变量)
class People(){ int age; //实例变量 static ID; //静态变量 }
3.6.2 实例变量与静态变量的区别
- 不同对象的实例变量不同
由于创建对象时会开辟出独立内存,所以一个对象实例变量的改变不会影响到其他实例变量 - 所有对象共享静态变量
创建多个对象时,静态变量的内存只有一块,一个对象改变静态变量,其他对象将受影响。 - 通过类名直接访问静态变量
java程序执行时,类的字节码文件会被加载到内存中,同时静态变量被分配了内存。所以不仅对象可以调用,类也可以直接调用静态变量。静态变量的内存直到程序退出才释放。
3.6.3 实例方法和静态方法
方法声明时,前面用static 修饰的就是静态方法
3.6.4 实例方法和静态方法的区别
-
对象调用实例方法
类的字节码文件被加载到内存中时,实例方法不会分配入口地址。只有该类创建第一个对象时,实例方法才分配入口地址,之后再创建对象就不再分配,所有对象共用实例方法。实例方法不能由类调用。 -
类名调用类方法
类的字节码文件被加载到内存中时,为静态方法分配了内存。
类可以直接调用静态方法:类名.静态方法; -
设计静态方法的原则
如果一个类不需要用到实例变量,可以将其方法设为静态方法,可以节省内存。
因为实例变量需要通过对象调用,一旦创建对象,就会为实例方法分配内存,占用资源。
3.7 方法重载
Java中有两种多态,重载(Overload)和重写(Override)
重载指类中有多个方法,方法名相同
- Overload规则
方法参数个数不同,或者个数相同但类型不同。 - 避免出现歧义
如果输入Dog.run(10,10),就会报错(对run的引用不明确)
必须像Dog.run(10.0,10)class Dog{ static void run(int m,double n){ System.out.println("The dog is running"); static void run(double m,int n){ System.out.println("狗在跑"); } }
3.8 this关键字
-
构造方法中使用this
构造方法中使用this,this代表使用该构造方法所创建的对象 -
实例方法中使用this
实例方法只能通过对象调用,当方法内使用this时,this代表使用该实例方法的对象this.成员变量
当静态变量在实例方法中出现时
类名.静态变量
当成员变量在方法中和局部变量名称相同时,前面必须加修饰
this
或类名
,其他情况可以省略this不能出现在静态方法中,因为静态方法可以直接用类调用,可能此时还没有对象被创建
3.9 包
包(package)的作用是区分有相同名称的类
3.9.1 import语句
如果两个类在同一包中,则可直接调用;如果在不同类的话,就需要用import导包
import 包名;
如果要调用一个包中所有类;
import 包名.*;
3.10 访问权限
3.10.1 修饰符
- private
只能在本类中使用
类A中如果用private修饰变量和方法,那么类A在类B中创建的对象不能调用该变量与方法
class A{
private int a;
}
class B{
A duiXiang = new A();
duiXiang.a = 3;//此处是非法调用,因为a是私有变量
}
-
public
公开的变量和方法,在其他类中可以用对象调用,也可以用类名点调用 -
protected
受保护的变量和方法,在同一包中可以调用。 -
友好变量和方法
不加修饰词的变量和方法,在同一包中可以调用(与protected的区别后面会讲)
3.10.2 基本类型的封装
java.lang 包中有基本类型的封装类:Byte、Short、Integer、Long、Float、Double、Character
可以使用它们的构造方法创建对象,如Integer(int i);
对象可以调用intValue()方法,返回对象含有的int型数据
其中Character类可以用类名调用一些方法:
Character.isLowerCase(i);//判断i是否小写字母
Character.toLowerCase(i);//将i改成小写字母
Character.isUpperCase(i);//判断i是否大写字母
Character.toUpperCase(i);//将i改成大写字母
3.11 对象数组
创建多个对象
Student [] stu;
stu = new Student[40];
仅仅声明了数组有40个元素,使用之前还要声明对象
stu[0] = new Student();