java基础
生活中处处都是学问,要时刻提醒自己不可懈怠,真正的大师永远都有一颗学徒的心,生活的背后要赋予行动,承担代价,我就是那个不撞南墙不回头的人,选择了就绝不轻言放弃。
内容:
每写一篇博客我都提几句励志的话语,激励自己写下去。
文章目录
前言
这篇博客是一些Java基础知识总结,当有知识点遗忘的时候,点进来查漏补缺,可供不同学习阶段的人们使用,有不精确的地方我也会改进,旨在与大家一起进步!一、Java基础语法
1、基础知识
public class Hello {
public static void main(String[] args) {
// 每个人的入门程序都是HelloWorld
System.out.println("HelloWorld!");
}
}
注释分为三种:
单行注释:使用 //
多行注释:/* …… */
文档注释:/** ……*/
包名:公司域名倒置作为包名
1.1、 标识符和关键字
标识符:类名、变量名、方法名
命名规范:
- 以字母(A-Z或者a-z)、美元符($)号、下划线(_)开始。
- 不能使用关键字作为方法名或变量名
- 标识符是大小写敏感的
- 可以使用中文命名,但是不建议,没有意义。
变量的命名规范
所有变量、方法、类名:见名知意
类成员变量:首字母小写和驼峰原则:goodBoy
局部变量:首字母小写和驼峰原则
常量:大写字母和下划线
类名:首字母大写和驼峰原则:
方法名:首字母小写和驼峰原则
关键字:
1.2、数据类型
8大基本数据类型:
byte 1个字节 范围:-128~127
short 2个字节 范围:-32768~32767
int 4个字节 范围:-2147483648~2147483647 正负21亿
long 8个字节:-2 ^ 63-1 ~ 2^63
float 4个字节
double 8个字节
char 2个字节
boolean 占1位 只有true和false
float类型后面要加个F,long类型后面需要加L,char类型使用单引号
数字之间可以用下划线分割(jdk1.7特性)
long num = 1263022222L;
float num2 = 3.14F;
科普:
字节:
位(bit):是计算机内部数据存储的最小单位。11001100是一个8位二进制数
字节(byte):是计算机处理数据的基本单位,用大写字母B表示
1B (字节)= 8 bit(位)
1bit 表示 1位
1Byte 表示一个字节 1B = 8b
1 KB = 1024B Kilo Byte
1 MB = 1024 KB Mega Byte
1 GB= 1024 MB Giga Byte
1 TB= 1024 GB Tera ByteT
1 PB = 1024 TB Peta Byte
1 EB = 1024 PB Exa Byte
1 ZB = 1024 EB Zetta Byte
1 YB= 1024 ZB Yotta Byte
后面BB NB DB CB,感兴趣可以自己去百度哈
全角字符和半角字符:
半角指一字符占用一个标准的字符位置,通常的英文字母、标点符号、特殊符号,阿拉伯数字等。 占一个字节
全角字符,汉字字符和规定了全角的英文字符及国标GB2312-80中的图形符号和特殊字符都是全角字符。 占俩个字节
进制:
二进制:只有0和1俩种数字
八进制:0-7
十六进制:0-9 A-F a代表10 f代表15 依次类推
二进制:0b开头
八进制:0开头
十六进制:0x开头
使用命令生成Java文档:
javadoc -encoding UTF-8 -charset UTF-8 Demo.java
java源码的位置:就在java安装目录下面的src.zip 解压就可以自己去瞅瞅了
引用数据类型:
除了基本类型,其他的数据类型都是引用类型
类型转换:
转换的时候可能存在内存溢出或精度问题
小数的优先级要要与整数
byte、short、char、---->int------>long------>float------>double
强制类型转换:(类型)变量名 高—>低
自动类型转换:原样即可 低—>高
不能对布尔值转换
1.3、运算符
- 算数运算符+、-、*、/、%、++、–
- 赋值运算符=
- 关系运算符>、<、==、>=、<=、!=、instanceof
- 逻辑运算符&&、||、!
- 位运算符 &、|、^、~、>>、<<、>>>
- 条件运算符 ? :
- 扩展运算符+=、-=、*=、/=
% 求出的是余数,/求出的数整数,^(异或)相同的为0不同的为1
<<左移 移几位乘2的几次方,>>右移几位除2的几次方, 2<<3 值为16 10----->10000 位运算效率高,>>>无符号右移
a:b?c 如果a=true则执行b,否则执行c
1.4、作用域
类变量
实例变量
局部变量
public class Demo1{
static int num=100; //类变量 全局有效
String str="aa"; //实例变量、成员变量
public void add(){
int i=10; //局部变量 局部有效
}
}
常量:final 数据类型 常量名 = 值; 常量名大写
1.5、修饰符
优先级:public > protected > default > private
public : 对所有类可见。使用对象:类、接口、变量、方法。
protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
2、流程控制
顺序结构
程序默认就是顺序结构执行,除非特别指明
选择结构
if-else
if-else if-else
switch
循环结构
while 先判断后执行
do……while 先执行后判断,至少执行一次
for jdk5引入了增强for循环
//普通for循环打印三角形
public static void printTriangle(){
for (int i=1;i<=10;i++){
for (int j=10;j>=i;j--){
System.out.print(" ");
}
for (int j=1;j<=i;j++){
System.out.print("*");
}
for (int j=1;j<i;j++){
System.out.print("*");
}
System.out.println();
}
}
1加到100,求和
@Test
public void testFor(){
int n=100;
int sum = (1+n)*n/2; // 还记得这个思路不
System.out.println(sum);
}
@Test
public void testFor1(){
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum+=i;
}
System.out.println(sum);
}
switch(expression){
case value:
//代码……
break;
case other:
//代码……
break;
default: //选
//默认
}
3、方法
System.out.println();是方法
Java方法是解决一类问题的步骤的有序组合
方法包含在类或对象中
方法在程序中创建,在其他地方被引用
设计方法的原则:保持方法的原子性,一个方法只完成一个功能,利于后期扩展
3.1、方法定义
修饰符 返回值类型 方法名(参数类型 参数名){
……
方法体
……
return 返回值;
}
参数:
形式参数与实际参数的区别:形式参数是定义时候在方法中写好的,实际参数是真实传递的数据
可变参数:
从jdk1.5之后,在方法声明中,在指定类型后面加一个省略号(一个方法中最多只能有一个可变参数,必须是方法的最后一个参数)
例如:求多个数之和,最少俩个数字
public static void add(int a,int b,int ...nums){
int sum= 0;
sum=a+b;
for (int i = 0;i<nums.length;i++){
sum +=nums[i];
}
System.out.println(sum);
}
3.2、方法调用
对象名.方法名();
有返回值的时候,定义一个变量接收它
无返回值,即返回值是void的时候,直接调用
方法重载:
重载:方法名相同,参数不同(参数的个数不同,参数的类型不同),返回值的类型可以不同。
public int add(int a,int b){
return a+b;
}
public double add(int a,int b,double c){
return a+b+c;
}
我们经常写的 System.out.println(); println()方法就是一个经典的重载案例
3.3、递归
递归:通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归头:什么时候结束递归,出口,必须要写递归头,不写的话容易陷入死循环
递归体:自己调用自己
求阶乘:
public static int f(int n){
if(n==1){ //递归出口
return 1;
}else{ //递归
return n*f(n-1);
}
}
4、数组
数组
创建数组的方式
一维数组:
int[] arr={1,2,3,4};
int[] arr1=new int[4];
二维数组:
int [][] arr2=new int[5][5];
int [][] arr3={{1,2,3},{4,5,6},{7,8,9}};
稀疏数组:当一个数组中大部分元素为0,或者是同一个值的数组时,可以用稀疏数组
稀疏数组的形式:
- 记录数组有几行几列,多少个不同的值
- 把具有不同值的元素和行列及值记录在一个小规模的数组中,从而缩小程序的规模
案例:
public static void main(String[] args) {
//创建一个二维数组
int[][] arr=new int[4][5];
arr[0][1] = 1;
arr[1][2] = 2;
arr[3][2] = 5;
//输出原始的数组
for (int[] ints : arr) {
for (int anInt : ints) {
System.out.print(anInt+"\t");
}
System.out.println();
}
System.out.println("----------------------------");
//转化为稀疏数组保存
//1、获取有效值的个数
int sum = 0;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
if(arr[i][j]!=0){
sum++;
}
}
}
System.out.println("有效值的个数为:"+sum);
//2、创建一个稀疏数组
int[][] arr1=new int[sum+1][3];
arr1[0][0]=arr.length;
arr1[0][1]=arr[0].length;
arr1[0][2]=sum;
//3、遍历二维数组,将非0的值存放到稀疏数组中
int count = 0;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
if(arr[i][j]!=0){
count++; //第0行存放的是 行数 列数 值的个数 这里自增是从第一行开始添加元素
arr1[count][0]=i;
arr1[count][1]=j;
arr1[count][2]=arr[i][j];
}
}
}
//4、打印稀疏数组
for (int i = 0; i < arr1.length; i++) {
System.out.println(arr1[i][0]+"\t"
+arr1[i][1]+"\t"
+ arr1[i][2]+"\t");
}
System.out.println("----------------------------");
System.out.println("稀疏数组还原:");
//1、读取稀疏数组的值
int[][] arr2=new int[arr1[0][0]][arr1[0][1]];
//2、还原元素值 从第1行开始,第0行存放得是 行数 列数 值个数
for (int i = 1; i < arr1.length; i++) {
arr2[arr1[i][0]][arr1[i][1]] = arr1[i][2];
}
//3、打印数组
for (int[] ints : arr2) {
for (int anInt : ints) {
System.out.print(anInt+"\t");
}
System.out.println();
}
}
效果截图:
5、类和对象
面向对象(OOP)的本质:以类的方式组织代码,以对象的组织封装数据
三大特性:封装、继承、多态
对象是具体的事物,类是抽象的。类是对象的模板。
程序设计追求:高内聚,低耦合
5.1、封装
封装 :将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的访问和操作。
其实就是:属性私有(private) set、get
意义:
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节,对成员变量进行精确的设定
- 统一接口
- 提高了系统的可维护性
示例:
public class Student {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
if(age<0||age>130){
this.age=1; //数据不合法
System.err.println("数据不合法!");
}else{
this.age = age;
}
}
}
5.2、继承
继承:减少代码的重复
java只有单继承,没有多继承
私有的东西无法被继承
语法: public class 子类 extends 父类{}
super与this:
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
this关键字:指向自己的引用。
区别:this没继承也可以调用,super只能在继承条件下才可以使用!
父类的功能子类不一定需要 Overide
重写:需要有继承关系,子类继承父类的方法
1. 方法名必须相同
2. 参数列表必须相同,方法体不同
3. 修饰符:范围可以扩大,但不能缩小
4. 抛出的异常:范围可以缩小,但不能扩大
5.3、多态
多态:同一个方法调用,由于对象不同,会有不同的行为!
注意事项:
1. 多态是方法的多态,属性没有多态
2. 存在条件:继承关系,方法重写,父类引用指向子类对象 Person p1 = new Student();
不可以重写的有:
1. static 方法,属于类,不属于实例
2. final 常量
3. private 方法
静态代码块:
static {
System.out.println("静态代码块!");
}
普通类:只有具体实现!
抽象类:具体实现和规范(抽象方法)都有!abstract
接口:只有规范! interface 实现接口 implements
接口中的方法 默认就是:public abstract
格式:返回值类型 方法名(参数);
一个Java文件可以有多个class文件,也属于内部类,只能有一个是public修饰的
public class A{
}
class B{
}
class C{
}
5.4、内部类
1. 成员内部类:类中在写一个类,可以访问外部类的方法和私有属性
2. 静态内部类:static修饰的内部类,只能访问外部类的静态方法和static属性
3. 局部内部类:写在方法中的内部类
4. 匿名内部类:不用将实例保存到对象中 new OuterClass().out();
1、成员内部类
public class OuterClass {
private int num;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public void out(){
System.out.println("外部类");
}
public void print(){
System.out.println("num = "+getNum());
}
//成员内部类
class Inner{
public void in(){
//可以获得外部类的私有属性 可以直接调用外部类的方法
System.out.println("内部类..."+getNum());
out();
}
}
}
测试:
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
outerClass.setNum(100);
outerClass.print();
OuterClass.Inner inner = outerClass.new Inner();
inner.in();
}
2、静态内部类
public class OuterClass {
public static void out(){ //加static
System.out.println("外部类");
}
static class Inner{
public void in(){
//不可以获得外部类的私有属性 不可以直接调用外部类的方法 无法访问非静态类方法
System.out.println("内部类...");
out();
}
}
}
3、局部内部类
public class OuterClass {
public void a(){
class Inner{
public void in(){
System.out.println("局部内部类");
}
}
}
}
6、异常
Throwable类有两个直接子类:
(1)Exception:出现的问题是可以被捕获的,检查性异常、运行时异常
(2)Error:系统错误,通常由JVM处理
Error、Exception 都继承了Throwable类
异常处理的关键字:try catch finally throw throws
try 执行的代码块
catch 用于捕获异常 若捕获多个异常的话,顺序从小到大!
finally 最终要执行的语句 可不写
throw 主动抛出异常,程序正常执行
throws 方法上抛出异常,程序停止
自定义异常:用的少,Java内置的异常类可以描述在编程时出现的大部分异常情况。
步骤:
- 创建自定义异常类
- 在方法中通过throw关键字抛出异常对象。
- 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理
- 在出现异常方法的调用者中捕获并处理异常。
//自定义的异常类
public class MyException extends Exception {
//传递数字 > 20
private int num;
public MyException(int num) {
this.num = num;
}
//toString 打印异常信息
@Override
public String toString() {
return "MyException{" + "num=" + num +",该数字大于20!"+ '}';
}
}
测试:
public class Demo1 {
public static void test(int a) throws MyException{
if (a>20){
throw new MyException(a);
}
System.out.println("OK!-->"+a);
}
public static void main(String[] args) {
try {
test(100);
} catch (MyException e) {
//处理异常代码块
System.out.println("自定义异常:"+e);
}
}
}
7、常用类
多看底层,运用了大量的重载方法
例如:
7.1、Math类
System.out.println(Math.sqrt(25)); // 5
System.out.println(Math.pow(5, 3)); //5的3次方 125
7.2、Random类
生成随机数
Random random = new Random();
int r = random.nextInt(10)+10; // 生成10到20之间的随机整数
System.out.println(r);
7.3、System类
常用的一些:
System类内部包含in、out和err三个成员变量,分别代表标准输入流(键盘输入),标准输出流(显示器)和标准错误输出流(显示器)。
Scanner scanner = new Scanner(System.in);
System.err.println("小屁孩!");
System.out.println("风华正茂!");
用于测试所用时间:currentTimeMillis 毫秒数 nanoTime纳秒数
long start = System.currentTimeMillis();//毫秒数
//代码块
long end = System.currentTimeMillis();//毫秒数
System.out.println("所用时间:"+(end-start));
System.nanoTime();//纳秒 同理
7.4、Date类
Date date1 = new Date();
System.out.println(date1); //默认输出当前时间 Wed Jan 27 10:22:48 CST 2021
Date date = new Date(); //创建日期对象
SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//SimpleDateFormat时间格式化
String now = sdf.format(date);
System.out.println(now); // 2021-01-27 10:22:48
7.5、String类
String a="15.88";
System.out.println(a);
// 切割小数点的时候 转义
String[] split = a.split("\\.");
System.out.println(split[0]);
System.out.println(split[1]);
测试生成随机数的时候
System.out.println(Integer.parseInt(String.valueOf(Math.random()*500).split("\\.")[0])+500);
System.out.println(Integer.parseInt(String.valueOf(Math.random()*500).split("\\.")[0])+500);
常用方法
replace() 字符串替换
replaceAll() 字符串全部替换
示例:正则表达式的使用
// 将所有非数字和字母的数据剔除掉
//String s1 = s.replaceAll("[^0-9a-zA-Z]", "");
replaceFirst() 把字符串的第一个字符替换为指定字符
split() 字符串切割
substring() 字符串截取
contains() 判断是否包含子字符串
concat() 字符串末尾拼接子串
endsWith() 是否以指定后缀结尾
startsWith() 是否以指定字符开头
length() 字符串长度
trim() 去除空格
intern() 将内容保存到对象池中
isEmpth() 判断是否为空
toLowerCase() 转小写
toUpperCase() 转大写
equals() 字符串比较
toCharArray 转化为字节数组
indexOf() 返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。
lastIndexOf() 返回指定字符在此字符串中最后一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1
伏笔:String.valueof() 和 toString() 以及使用 (String) 强转 三者有什么区别?
测试
1s=1000毫秒=1000000微秒=1000000000纳秒
毫秒和纳秒 currentTimeMillis和nanoTime
纳秒控制的进度较细粒度,现在的计算机速度很快,有时候使用毫秒,测试出的时间差别很小
long l = System.nanoTime(); // 纳秒 1s=1000毫秒=1000000微秒=1000000000纳秒
long start = System.currentTimeMillis(); // 毫秒
System.out.println(new Test5().singleNumber(s2));
long end = System.currentTimeMillis();
long l2 = System.nanoTime();
System.out.println("消耗时间:"+(end-start)); // 0
System.out.println("消耗时间:"+(l2-l)); // 244500