本系列适合有C++/Python/Golang等编程基础的同学,对JAVA基础知识进行归纳总结。
前言
JAVA作为一门编程语言,分为三个版本。
SE标准版,包含基础语法、多线程、IO流等核心类;
EE企业版,包含SE的基础上还有扩展部分如Spring、mybatis、JDBC等;
ME微型版,包含SE的部分类库,又有自己的扩展,包含移动类、嵌入式开发等等。
一、JAVA基本编程结构
1、Hello World!
对于一个编程菜鸟而言,学习编程语言的第一站便是hello world。
public class HelloWorld{
public static void main(String[] args){
System.out.println("Hello World");
}
}
1)类名必须以英文字母开头,习惯上首字母大写,驼峰命名法;
2)public代表公开访问,没有它,则程序无法在命令行执行;
3)程序入口函数必须是static静态方法,函数名是main,参数类型为String[];
4)文件名必须和公开类的名字一样,并以.java结尾;
5)main函数不需要返回值,因此void类型。
然后我们要开始运行程序了。使用javac HelloWorld.java编译程序;使用java HelloWorld来运行编译生成的HelloWorld.class程序即可。有关其涉及底层原理会在JVM、内存管理等后续章节中叙述。
2、数据类型
JAVA中的数据类型有基本类型和引用类型两种。下面说的皆是变量,对于常量可以使用final关键字来修饰,如final Double PI=3.1415926;
基本类型包括整数类型、浮点数类型、字符类型、布尔类型。
整数类型:byte占一个字节,short占两个字节,int占四个字节,long占8个字节。类型转换时只能由数据范围小的转换为数据范围大的。值得注意的是,由于虚拟机的存在,不管在32位还是64位系统上,java的数据类型都是一样的,和C++区分开。
浮点数类型:Double占8字节,float占4字节。float在表示时需要在后面加上f后缀。特殊的浮点值NaN代表非数字,比如if(Double.isNaN(x))代表判断x是否是一个数字。对于浮点数是否相等,可以使用Math.abs(x-y)<0.00001来判断。
字符类型:char占两个字节。使用单引号。
布尔类型:boolean只有true与false两种,理论上1bit即可,但JVM中使用4字节表示。与C++不同,不能用0,1表示false,true。
引用类型是除基本类型以外的类型。包括数组、类、接口、枚举、注解,会在之后详解。
这里说明一下二者的区别:首先,java中数据的存储是在堆中开辟内存,保存对象基本信息,在栈中只保存堆内存地址。基本类型是直接存储在内存栈上,而引用类型是继承自Object类,“引用”存储在栈上、具体值存储在堆上。另外一个区别是,基本类型在传参时,形参修改,实参不变;引用类型直接指向实际值的地址,形参修改,实参改变。
其他类型如果整型和浮点型不能满足数值范围要求,可以使用Math包中的BigInteger与BigDecimal。BigInteger a=BigInteger.valueOf(100);//将基本类型转化成大数据类型。注意由于java没有运算符重载,因此不能使用+,*,需要用add,multiply来替代。除法取余操作亦是如此,可自行查阅资料。
3、数组与字符串
数组类型是引用类型,可以使用int[] ans=new int[5];或者int[] ns=new int[]{1,2,3,4,5}来定义。数组中某个元素发生修改时,栈中存储的地址,会重新指向一个新的堆内存,该内存中存放修改后的元素。数组遍历有两种方案,一种是for(int i=0;i<ans.length;i++)一种是for(int n:ans),与C++极为类似。值得注意的是,java中由于内存分配的关系,数组实际上是一维数组,每个元素可以使不同大小的数组,即不规则数组,这与C++不一样。
数组中常用的函数包括:int x=Arrays.binarySearch(ans,target)表示使用二分查找,找出已排序数组中等于目标值的元素的索引,没有则返回-1;Arrays.fill(ans,val)用val来填满整个数组;Arrays.sort(ans)。这里需要导入Arrays包,import java.util.Arrays;
补充:字符串类型,字符串类型String是引用类型,本身是class,内部是通过char[]数组实现。一般我们直接定义为String s1="Hello",底层是String s1=new String(new char[]{'H','e','l','l','o'});JAVA提供了如前者一样的字面量来实现。
JAVA的字符串最大特点是不可修改,当修改其中一个char时,相当于重新new一个字符串,重新指向新的堆内存。这里和golang比较相像。
字符串的拼接可以使用+号,问题是,在一个循环中,每次都会重新创建一个字符串对象,然后使用并抛弃,影响GC效率。可以使用StringBuilder或StringJoiner预分配缓冲区来解决。
//使用StringBuilder
StringBuilder s = new StringBuilder(1000);
for (int i = 0; i < 800; i++) {
s.append(i);
}
String s = s.toString();
//使用StringJoiner
String[] n = {"A", "B", "C"};
var s = String.join(", ", n);
一般的拼接使用StringBuilder即可,但对于分隔符的情况使用StringJoiner更合适,由于原本的StringJoiner需要指定头部和尾部,因此可以用join方法来快速拼接。
字符串常用函数包括(仅列出6种,其余在用到时学习):
String s="Hello!";
//获取子串
String s1=s.substring(0,3);
//判断s是否以s1为后缀
boolean s2=s.endsWith(s1);
//判断s是否以s1为前缀
boolean s3=s.startsWith(s1);
//将s中全部大写变为小写
String s4=s.toLowerCase();
//将s中全部小写变为大写
String s5=s.toUpperCase();
//将s中所有子串l变为目标串s1
String s6=s.replace('l',s1);
4、数值计算与流程控制
java中运算操作、流程控制与C++中极为类似,在此不一一赘述。需要注意以下几点:
1)==:当我们判断两个对象是否相等时,常使用==。在java中,基本类型可以,但引用类型不行,显然,==仅比较在栈空间的引用类型的“名称”,怎么可能相等呢?要想深度比较,就要使用equals()函数。
String s="Hello";
String t=s;
System.out.println(s.equals(t));//不忽略大小写
System.out.println(s.equalsIgnoreCase(t));//忽略大小写
2)C++中>>不能保证执行的是逻辑运算还是算术运算,java则彻底区分开,使用>>进行算数运算,使用>>>进行逻辑运算。
3)java提供了常用的函数。Math.sqrt(x)计算一个数的平方根;Math.pow(x,a)计算x的a次方;还用Math.PI、Math.E等常量;还有Math.sin、Math.cos等函数。
二、JAVA类与对象
1、面向对象的语言
与C++一样,java是面向对象的语言。类是实现的核心,类与类之间的关系有多种。
继承 is-a 是一个特定类与一般类之间的关系,类似于OS中的父子进程;依赖 uses-a 是指偶然、临时性的使用,如一个类中的某个方法使用了另一个类作为参数;关联是两个类之间的强依赖关系,比如一个类成为了另一个类的私有属性,其中一个特例是聚合 has-a ,两个类是有实际关联的,如家庭-孩子、衣服-裤子之类的,另外一种是组合 contains-a ,则是更上一层,头颅-眼睛这种,一个生命周期结束导致另一个也随之结束,这两种只能从语义上进行区分。详细内容可查阅相关书籍,或使用类图自行学习。
2、构造一个类要做什么
这里会分析构造一个最基础的类需要实现什么。
一个类的实现无非就三部分:构造器、方法、字段。
1)构造器
一个构造器的实现必须注意以下几点:
①构造器的名字与类名相同;
②一个类可以有多个构造器、构造器参数可以有多个;
③构造器必须和new一起被使用。
同C++,类的多个构造器也是使用了重载:多个方法具有相同的名字但含有不同的参数,便发生了重载。需要牢记的是,一个类含有多个构造器但没有默认构造器,在调用无参构造是是不合法的。
在构造器方法或其他方法中,有两类参数:一类是隐式参数用this指代类的对象,一类是显示参数,即方法名后面的参数列表。构造函数内,参数的初始化可以使用this来实现,同C++。另外this有另一个作用,便是在一个构造器的第一句使用this(...)调用另一个构造器,这一点与C++不同。
除了在构造器中初始化数据外,还有声明赋值来初始化。另外,可以使用初始化块来实现。在java中用{}表示隔离,通过{}初始化块,可以实现,当构造器构造对象后,先初始化,在执行其余部分内容。常用于静态字段初始化,下面便是不使用main函数便可以执行函数:
...
public class Hello{
static{
System.out.println("Hello World!");
}
}
...
与C++不同,java没有析构函数,可以通过GC来实现垃圾回收。这一点和golang一样,果然业务代码还是需要java/golang这样有大量优化、简易处理、语法糖的编程语言啊。
2)方法与字段
编程中对一个实例字段的读写一般通过三个步骤实现:一个私有的数据字段private String name、一个公开的字段访问方法String getName(),一个公开的字段调节器方法void setName。(ps:方法一般小驼峰,类一般大驼峰)。注意,调节器方法一般不要返回可变对象,否则容易破坏封装关系报错。ps:final修饰的字段是不可改变的,如果一个类的所有字段都是final,即为不可改变的。
静态字段:被static修饰,一个字段只属于这个类,不属于任何对象。一般静态常量比较常见,公开字段很危险,但公开常量字段却没问题,别人只能只读访问,如Math.PI。静态方法:被static修饰,不需要任何对象便可以执行,没有this参数。如Math.pow()。直接使用类名来指代即可。
方法的参数传递:java只有基本类型与引用类型两种,方法不可能改变值类型的参数,引用类型则可以。比如在tom.changeMoney()函数中,直接传递数据是无法改变tom这个实例的钱的,因此需要通过传递新建的实例对象,加上正确的方法来实现。
总结
本文主要对java基础知识以及部分类与对象的内容进行归纳总结学习。后续将基础部分更新完,对于SSM、微服务相关将不会细致更新(时间紧迫,秋招后会慢慢更新、学习),而是将我遇到的疑惑以及解决方法更新在博客上,有任何问题欢迎与我评论、私信交流。