JAVASE(java基础)
由于学JAVA安全路上频频碰壁,所以还是打算静下心来将开发好好学一学。
推荐视频:【【狂神说Java】Java零基础学习视频通俗易懂】https://www.bilibili.com/video/BV12J41137hu?p=17&vd_source=111e3860debf30d0b82773b14cf055b6
有学过C++这种面向对象的编程语言的,可以2倍速跳着看,两天左右的时间便能过完。
声明:以下内容旨在JAVA快速入门,所以写的比较简陋,还是推荐快速看一遍视频自己总结。
JDK JRE JVM
JDK:Java Development Kit(JAVA开发者工具)(JDK包含JRE于JVM)
JRE:Java Runtime Environment(Java运行时环境)(包含JVM)
JVM:JAVA Virtual Machine(Java虚拟机)(跨平台主要通过的就是JVM)
环境部署
环境部署我就不赘述了,网上非常多教程。或者看我推荐的视频即可。需要idea破解版的可以私聊我。
Hello World
新建一个helloworld.java
内容如下
public class helloworld {
public static void main(String[] args) {
System.out.println("Hello world");
}
}
System.out.println便是java中的输出语句。class 后面的名称要与文件名一样
编译
javac helloworld.java
编译成功会生成helloworld.class
运行
java helloworld
运行成功会输出Hello world
Java程序的运行机制
java运行的全过程
Java源代码—->编译器—->jvm可执行的Java字节码(*.class文件)—->jvm(类装载器)—->字节码校验器 --> jvm中解释器—–>机器可执行的二进制机器码—->程序运行。
java与C++的区别:
- 都是面向对象的语言,都支持封装、继承和多态
- Java不提供指针来直接访问内存,程序内存更加安全
- Java的类是单继承的,C++支持多重继承;虽然Java的类不可以多继承,但是接口可以多继承。
- Java有自动内存管理机制,不需要程序员手动释放无用内存
Java基础语法
注释
单行注释 //
多行注释 /*内容*/
文档注释 /** 描述内容*/
快捷键ctrl+/
标识符
关键字
与其他变成语言一样,java也是有定义好的关键字。
这些关键字便不能作用变量名,类名以及方法名了。

规范
其实与其他编程语言的规范差不多,只有略微的区别

数据类型
JAVA与C++一样是强类型语言:要求变量的使用严格符合规定,所有变量都必须先定义后使用。
弱类型语言:JS,php等
JAVA的数据类型分为两大类:
与C++依旧非常的相似
- 基本类型:
- 整数类型
- byte:占1字节
- short:占2字节
- int:占4字节
- long:占8字节
- 浮点类型
- float:占4字节
- double:占8字节
- 字符类型
- char:占2字节
- 布尔类型
- boolean:占一位,值只有true或false
- 引用数据类型
- 类(class)
- 接口(interface)
- 数组
进制表示:
十进制:10
八进制:010
十六进制:0xa
类型转换
类型的强度
从低到高:
byte,short,char->int->long->float->double
分为强制类型转换与自动类型转换:
- 强制类型转换
高类型向低类型转换用强制类型转换,但是可能会出现内存溢出的问题或者精度的问题
(类型)变量名
- 自动类型转换
低向高使用自动类型转换
int i = 128;
double b = i;
输出:
i =128;
b = 128.0;
变量
语法:
type identifier [ = value][, identifier [= value] ...] ;
// 数据类型 变量名 = 值;
与C++基本一致。
int a, b, c; // 声明三个int型整数:a、 b、c
int d = 3, e = 4, f = 5; // 声明三个整数并赋予初值
byte z = 22; // 声明并初始化 z
String s = "runoob"; // 声明并初始化字符串 s
double pi = 3.14159; // 声明了双精度浮点型变量 pi
char x = 'x'; // 声明变量 x 的值是字符 'x'。
变量作用域
变量的作用域分为三种:
- 类变量:静态变量是指在类中定义的一个变量,它与类相关而不是与实例相关
- 成员(实例)变量:成员变量声明在一个类中,但在方法、构造方法和语句块之外。
- 局部变量:局部变量是在方法、构造方法或语句块内部声明的变量
public class Variable{
static int allClicks=0; //类变量
String str="hello world"; //实例变量
public void method(){
int i =0; // 局部变量
}
}
学过C++这个便很好理解。
常量
常量:不会变的值,可以理解为特殊的变量只不过值不能被更改
final 常量名=值;
基本都声明为类变量
static final double PI=3.14
运算符
与C++基本一样。

int b = a++; 先赋值后a+1
int b = ++a; 先a+1后赋值
但是JAVA中并没有幂运算的运算符。
一般我们2的三次方会写成:2^3(c++)或者2**3(python)
但是在JAVA中并不支持
这个时候便要用到JAVA中的Math类
这时候2的三次方便可以写成
Math.pow(2,3)
Math中还有很多数学中的运算方法。
有关运算符便没有啥要注意的地方了,跟C++用法基本一致。
包机制
为了更好的组织类,Java中提供了包机制,用于区别类名的命令空间。
语法格式:
package pjg1[.pkg2[.pkg3...]]
一般使用公司的域名的倒置作为包名。
为了能够使用某一个包的成员,我们需要在代码中明确导入该包。使用import便能导入。
import com.baidu.*
导入包里所有的包
JavaDoc
javadoc命令是用来生成自己API文档的,其实跟我们前面讲的文档注释

在方法前面加上/**回车,便会自动生成一些参数信息
可以通过命令行生成
javadoc --encoding UTF-8 -charset UTF-8 Doc.java
运行后便会生成一堆文档相关的文件。
也可以通过IDEA生成

Scander对象(用于用户输入)
通过Scanner类我们可以获取用户输入。
需要导入的包
import java.util.Scanner;
基本语法
Scanner s = new Scanner(System.in);
有两种获取输入的方式
next():不能获得带有空格的字符串
nextLine():以Enter为结束符,获取的内容更全面,推荐使用
nextInt():获取输入的一个整数数据
nextFloat():获取输入的一个float小数数据
其他数据类型的输入同理
配套使用的用于检测后面是否还有数据的方法
hasnext()
hasnextLine()
......
例子:
import java.sql.SQLOutput;
import java.util.Scanner;
public class helloworld {
public static void main(String[] args) {
// 创建一个扫描器对象,用于介绍键盘数据
Scanner s = new Scanner(System.in);
System.out.println("使用next方式接收数据");
//判断用户有没有输入字符串
if(s.hasNext()){
//使用next方式接收
String str = s.next();
System.out.println("输出的内容为:"+str);
}
//凡是属于IO流的类如果不关闭就会一直占用资源
s.close();
}
}
例子:输入多个数字并计算平均值
import java.sql.SQLOutput;
import java.util.Scanner;
public class helloworld {
public static void main(String[] args) {
// 创建一个扫描器对象,用于介绍键盘数据
Scanner s = new Scanner(System.in);
double sum = 0;
int m=0;
//判断用户有没有输入字符串
while(s.hasNextDouble()){
//使用next方式接收
double dou = s.nextDouble();
sum+=dou;
m++;
}
System.out.println(sum/m);
//凡是属于IO流的类如果不关闭就会一直占用资源
s.close();
}
}
注意要输入一个不是double的数据类型才会结束读取

流程控制
顺序结构
JAVA基本结构就是顺序结构,除非特殊声明,否则就是按照顺序一行一行执行。
if选择结构
单选择:
if(条件){
执行语句;
}
双选择:
if(条件){
执行语句;
}
else{
语句;
}
多选择:
if(条件){
执行语句;
}
else if(条件){
语句;
}
else if(条件){
语句;
}
else{
语句;
}
没什么好讲的,与C++基本一样,但是怎么需要注意,判断字符串相等尽量使用.equals
s.equals("hello");
Switch选择结构
switch(expression){
case value:
语句;
break;
case value:
语句;
break;
defalut:
语句;
}

用法与C++一样。
循环结构
依旧与java差不多
while循环
int i=0;
while(i<100){
i++;
}
do while循环
do{
}while(循环条件)
for循环
for(初始化;循环条件;更新){
}
for(int i=0;i<100;i++){
System.out.printIn(i);
}
增强for循环:
主要用于数组或集合
int[] nums = {1,2,3,4,5}
for(int x:nums){
xxxx;
}
很像python中的
for x in String:
break,continue,goto
依旧与c++用法一样
break:结束当前层循环
continue:结束执行下面的语句进入下一次循环
goto:跳转到指定位置执行
方法
其实就是C++中的函数
定义语法:
修饰符 返回类型 方法名(传入形参1,传入形参2,....){
方法体。
return 返回值;
}
修饰符:public,protected,private,static
//定义add方法
public int add(int a,int b){
return a+b;
}
public static void main(String[] args) {
//调用方法
int a = add(1,2);
}
方法的重载
在JAVA中也支持方法的重载,就是函数名是相同的,但是传入的形参不相同。编译器会根据,参数的类型和个数,匹配对应的重载函数。
比如我们再来一个
public int add(double a,double b){
return a+b;
}
doule b = add(1.0,2.0);
这个时候调用的便是以double为参数的方法
命令行传递参数
有时候希望运行程序的时候再传递给它消息。这要靠传递命令行参数给main()函数实现。
比如我们的main方法也是可以传参的
import java.sql.SQLOutput;
import java.util.Scanner;
public class helloworld {
public static void main(String[] args) {
for(int i =0;i<args.length;i++){
System.out.printIn("args["+i+"]: "+args[i]);
}
}
}
通过命令行
java 包名.helloworld this is k1rito
直接在后面丢东西便能传递参数
可变参数
如果一个方法想要传各种个数的参数,如果全都用重载函数的话便太繁琐了。
从JDK1.5开始,java便支持传递同类型的可变参数的一个方法,允许传递任意个数的同类型参数。
在方法声明中,在指定参数类型后加一个省略号(...)。
public static double add(double ... numbers){
.....
}
上面这个方法就能实现传递任意多个double类型,然后实现相加。
一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通参数都必须在它之前声明。
public static double add(int a,double ... numbers){
.....
}
静态方法,非静态方法
静态方法:
可以使用通过类名.方法名调用
Student.sayhello()
非静态方法,必须先实例化后再调用
Student stu = new Student();
stu.sayHello();
递归方法
每种编程语言的递归原理都一样,这属于算法的范畴,这里便不解释了。
数组
数组是相同类型数据的有序集合
其中每一个数据称作一个数组元素,每个数组元素可以通过下标来访问。
声明与创建
定义:
dataType[] arrayRefVar; //首选方法
或
dataType arrayRefVar[]; //效果相同,但不是首选方法
创建:
int[] nums;
nums=new int[10];
//赋值
nums[0]=1;
nums[1]=2;
获取数组长度
nums.length
三种初始化
静态初始化:
int[] a = {1,2,3};
Man[] mans = {new Man(1,1),new Man(1,2)};
动态初始化:
int[] a =new int[2];
a[0]=1;
a[1]=2;
默认初始化:
数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量相同的方式被隐式初始化。一般都初始化为0;
int []a = new int[2];
System.out.printIn(a[0]);
输出0
数组的基本特点

数组遍历
for(int i = 0;i<a.length;i++)
{
System.out.printIn(a[i]);
}
或者使用增强for循环
for(int array : a){
System.out.printIn(a[i]);
}
反转数组
public static int[] reverse(int[] arrays){
int[] result = new int[arrays.length];
for(int i = 0,j=result.length-1;i<arrays.length;i++,j--){
result[j]=arrays[i];
}
return result;
}
二维数组
与C++一样
int[][] a = new int[2][5];
int[][] a = {{1,2},{3,4}......};
取元素
a[0][1];
Arrays类
数组的工具类
java.util.Arrays
该类包含用于数组操作的各种方法,如排序和搜索。
常用的方法
Arrays.toString:打印数组元素
Arrays.sort:对数组排序,升序
....
还有很多别的方法,可以看官方文档
冒泡排序啥的就不说了,别的编程语言都有讲过
稀疏数组
当一个数组中大部分元素为0或者是同样的数组
稀疏数组的处理方式是:
-
记录数组一共有几行几列,有多少个不同的值
-
把既有不同值的元素和行列及值记录在一个小规模数组中,从而缩小程序的规模。
如下图

算法实现便不在这讲了,我其实自己算法也比较垃圾,等以后有时间肯定要刷一刷力扣
面向对象
前面其实都算基础,面向对象才是JAVASE中的关键。
面向对象编程的本质:以类的方式组织代码,以对象的组织封装数据。
三大本质:
封装,继承,多态
面向过程&面向对象
面向过程思想:
步骤清晰简单,第一步做什么,第二步做什么,适合处理简单问题。
面向对象思想:
分类的思维模式,思考问题首先会解决问题需要哪些分类,对分类进行单独思考。
对于描述复杂的事物,为了宏观把握,从整体上合理分析,我们使用面向对象的思路来分析。
到那时具体到围观操作,需要面向过程实现。
类与对象的创建
新建java文件,便是创建了一个文件名的类。
至于属性与方法的定义与C++无异。
对象的创建也跟c++一样
Student stu = new Student();
构造器
构造器是类用于new实例化对象时进行,一般用于初始化。
一共类即使什么都不屑,也会存在一个无参的构造函数。
构造器与方法一样,都可以重载。
但是一旦你定义了有参构造,就必须自己显示定义无参构造留空也可以,但是必须要定义,不然无法使用无参构造。
封装
封装说白了就是讲属性设置为私有,然后通过特定的接口来获取。
比如说name是私有属性,但是提供一个public的方法getName可以获取name。或者通过set来设置name。
总结:属性私有,get/set
alt+insert快捷键可以自动生成get/set方法
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
封装的作用:
提高了程序的安全型,隐藏了代码的实现细节,统一了接口,系统可维护增加了
与单例模式息息相关
继承
继承就是当你有一个类其中很多的属性与方法都与另一个类重合,为了避免大量重复的定义,可以选择从另一个类继承来。
比如说动物是一个类它包含各种动物通用的属性与方法,但是动物中又有很多,比如猴子,兔子...。这时候猴子其实就是从动物继承而来,称之为动物的子类。
class 父类 {
}
class 子类 extends 父类 {
}
但是继承与属性的修饰符有关
类中有如下这些修饰符
default:不写修饰符默认是default
public:公开
private:私有
protected:受保护的
父类中的private属性与方法都不会被继承。
JAVA只能单继承,但是可以多重继承,就是B继承自A,C继承自B。

所有的类都直接或间接继承自Object类,这是所有类的父类。所以我们的类可以直接调用很多方法。
Super的使用:
当子类中又定义了一个与父类中继承下来的属性名相同的属性,这个时候怎么获取到继承的属性。
name
this.name
以上两种获取的都是子类中的name
super.name
这种方式获取的便是父类中的name
同理方法也是这个道理
name.print()调用子类的print
super.print()调用父类的print
并且还有一个细节:
当你通过new创建一个子类的对象时,如果是无参的话,会先调用完父类的无参构造(隐藏的代码),然后才会调用完子类的无参构造。
方法的重写
重写:需要有继承关系,子类重写父类的方法。
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大,但是不能缩小
- 抛出的异常:范围,可以被缩小,但不能扩大
子类方法与父类方法一致,方法体不同。
static方法属于类,它不属于实例,所以不能重写。
final修饰的也不能重写。
private修饰的也不能重写。
多态
多态就是同一个接口,使用不同的实例而执行不同操作。
例子:
Student类
public class Student extends Person{
public void run(){
System.out.printIn("son");
}
public void eat(){
System.out.printIn("eat");
}
}
Person类
public class Person extends Person{
public void run(){
System.out.printIn("dad");
}
}
一个类型的实际类型是确定的
new Student();
new Person();
但是可以指向的引用类型就不确定了:父类的引用指向子类
//Student能调用的方法都是自己的或者继承父类的
Student s1 = new Student();
//person 父类型,可以指向子类,但是不能调用子类独有的方法
Person s2 = new Student();
s2.run(); //子类重写了父类的方法,执行子类的方法,返回son
s2.eat(); //报错,无法执行子类独有的
Object s3 = new Student(); //Object父类引用指向子类
注意事项:
多态是方法的多态,属性没有多态。
存在条件:
- 继承
- 重写
- 父类引用指向子类对象:Person s2 = new Student();
多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。
instanceof
用法:用来判断左边是否是右边的实例或后代
//Object>Person>Student
Object object = new Student();
System.out.printIn(object instanceof Student); //true
System.out.printIn(object instanceof Person); //true
System.out.printIn(object instanceof Object); //true
System.out.printIn(object instanceof Teacher); //false
System.out.printIn(object instanceof String); //false
X instanceof Y
能否编译通过主要看
类型的转换
低转高直接转换,高转低要强制类型转换
//高 低
//低向高转换直接转换
Person obj = new Student();
//但是obj无法调用Student专属的go方法.这时候要高向低转换。将Person类型转换为Student类型便能使用go方法了,这时候是高向低转换,要前置类型转换
Student student = (Student)obj;
student.go();
或者
((Student)obj).go();
抽象类
声明
public abstract class Action{
//约束,有人帮我们实现
//abstract,抽象方法,只有方法的名字,没有方法的实现。
public abstract void doSomething();
}
抽象类的所有方法,继承了它的子类,都必须实现它的方法,除非子类也是抽象的,那么便让子子类实现。
特点:
- 不能new出来,只能通过子类实现它:约束!
- 抽象类里可以写普通方法,抽象方法必须写在抽象类中
接口
抽象的思维
我们都知道在JAVA中的类只能是单继承并不能实现多继承,但是接口不一样,接口可以多继承。

接口声明的关键词是interface
public interface UserService{
//接口中的所有定义其实都是抽象的public abstract
void run();
public abstract run();
}
接口一般都要有实现类
//类可以实现接口,implements 接口
实现了接口的类,就需要重写接口中的方法
public class UserServiceImpl implements UserService{
public void run(){
实现;
}
}
接口可以多继承
//利用接口实现多继承
public class UserServiceImpl implements UserService,TimeService{
public void run(){
实现;
}
public void time(){
实现;
}
}
在接口中定义的属性都是静态的常量。
作用:
- 约束
- 定义的一些方法,让不同的人实现,接口都需要实现类
- 接口不能被实例化,接口中没有构造方法
- implments可以实现多个接口
- 必须要重写接口中的方法
内部类
类里面也能定义类,这个类里面可以访问外部类的私有属性与方法。
//局部内部类
public class Outer{
public class inNner{
}
}
内部类的实例化:
Outer.inNner = new Outer();
也可以在一个java文件写定义类
public class Outer{
}
class inNner{
}
异常机制
程序在运行过程中,非常可能遇到一些问题比如文件不存在,舒服不符合要求,内存满了等等,我们称之为异常(Exception)。
异常发射管在程序运行期间,影响了程序正常进行。
异常体系结构
Java中把异常当作对象处理,并定义了一个基类java.lang.Throwable作为所有异常的超类。
在Java API中定义了很多的异常类,这些异常类分为两大类,错误Error(能避免)和异常Exception(尽量避免)。

Error
Error类对象有Java虚拟机生成并跑出,大多数错误与代码编写者所执行的操作无关。
Exception

抛出、捕获异常
异常处理的五个关键字
try、catch、finally、throw、throws
public class Test{
public static void main(String[]args){
int a=1;
int b=0;
//假设要捕获多个异常:从小到大
try{//try监控区域
System.out.printIn(a/b);
}catch(ArithmeticException e){//catch(想要捕获的异常类型)捕获异常,可以套多个catch,但是最大的比如Throwable要放在最下面
System.out.printIn("程序出现异常,除数不能为0");
}finally{//可以不用,这是没有异常执行的语句
System.out.printIn("finally");
}
}
}
自动生成
选中代码ctrl+alt+T
选择try catch finally
主动抛出异常
关键字throw与throws
throw用在方法内
throw new ArithmeticException();
假设这个方法中处理不来这个异常,便在方法上用throws抛出异常
public void test(int a,int b)throws ArithmeticException{}