前言
本文是学习 Java 过程中所作的知识点总结,希望能给大家一些快速参考。
Hello World
配置环境
假如 JDK 解压缩后的包在 /home/cunyu/soft/jdk-11.0.7 目录,则在 /etc/profile 文件中加入如下配置:
JAVA_HOME = /home/cunyu/soft/jdk-11.0.7
PATH = $JAVA_HOME/bin:$PATH
命令行运行程序
# 编译 javac HelloWorld.java # 运行 java HelloWorld
面向对象
类和对象
public class Item{ // 物品名 String name; // 价格 int price; public static void main(String[] args){ Item hp = new Item(); hp.name = "血瓶"; hp.price = 50; Item shoes = new Item(); shoes.name = "草鞋"; shoes.price = 300; Item sword = new Item(); sword.name = "长剑"; sword.price = 530; } }
方法
public class Item{ // 物品名 String name; // 价格 int price; // 血量 float hp; public legendary(){ System.out.println("超神"); } public float getHp(){ return hp; } public void recovery(float blood){ hp += blood; } }
变量
基本数据类型
总共有 8 大基本数据类型
整性
byte,1 个字节,8 位
short,2 个字节, 16 位
int,4 个字节,32 位
long,8 个字节,64 位
浮点型
float,4 个字节,32 位
double,8 个字节,64 位
字符型
char,2 个字节,16 位
布尔型
boolean,1 位
字面值
给基本数据类型变量赋值的方式叫做 字面值;
类型转换
转换规则
从小达到自动转,从大到小强制转;
高精度向低精度转换,可能导致溢出;
低精度可以向高精度转换;
不同数据类型之间相互转换需要进行 强制转换;
命名规则及建议
变量命名只能使用 字母、数字、_、$;
变量第一个字符只能 字母、$、_,不能是 数字;
变量命名不能使用关键字,但可以包含关键字;
尽量使用完整单词,而非缩写;
块
Java 中 {} 包括的部分,称为一个块;
作用域
字段、属性、Field
当变量声明在 类下 时,叫做 字段,或者 属性、成员变量、Field,作用域 从声明的位置开始的整个类;
参数
当变量声明在 方法上 时,叫做 参数,作用域为 该方法内所有代码,其他方法和类都不能访问;
局部变量
当变量声明在 方法内 时,叫做 局部变量,作用域为 从声明的位置开始,直到所处于的块结束;
final 修饰符
当声明一个用 final 修饰的变量时,说明该变量 有且只有一次赋值的机会;
操作符
算数操作符
+、-、×、/、%、++、--
当不同的运算单元(任一长度超过 int)进行运算时,最终返回结果按照最长的长度计算;
当不同的运算单元(任一长度不超过 int)进行运算时,最终返回结果按照 int 计算;
++、-- 前置时,先运算,再取值;后置时、先取值,再计算;
关系操作符
>、>=、<、<=、==、!=
逻辑操作符
&、&&、|、||、!、^
长路与短路的区别:长路会运算符两边的值均进行运算,短路当运算符左侧为 false 时,运算符右侧则不再计算;
位运算符
Integer.toBinaryString()、|、&、^、~、<<、>>、>>>
>> 与 >>> 的区别
>> 会将正数所有位右移,并在最前面补 0,会将负数所有位右移,并在最前面补 1;
>>> 会将负数的二进制的第一位的 1 也向右移动,然后在前面补 0,从而导致负数在无符号右移后,得到一个正数;
>> 移动后数的正负性不变,>>> 移动后变为正数;
三元操作符
表达式?值1:值2,当表达式为真时,返回值1;当表达式为假时,返回值2;
控制流程
switch
switch 中可以使用 byte、short、int、char、String、enum;
每个表达式结束都应该有一个 break;
使用 String 的实质还是使用正数,是通过编译后将其转化为 hash 值;
数组
创建数组
数组是一个 长度固定,包含 相同类型 数据的 容器;
若一个变量代表一个数组,则将这个变量叫做 引用;
// 声明一个引用
int[] arr;
// 创建一个长度为 10 的数组,且使用引用 arr 指向该数组
初始化数组
分配空间与赋值同步
//分配长度为 5 的数组,但未赋值 int[] a = new int[5]; //没有赋值,那么就会使用默认值,作为int类型的数组,默认值是0 System.out.println(a[0]); //进行赋值 a[0] = 100; a[1] = 101; a[2] = 103; a[3] = 120; a[4] = 140;
- 分配空间同时赋值
// 方式 1,分配空间同时赋值 int[] arr1 = new int[]{100,102,444,836,3236}; // 方式 2 int[] arr2 = {100,102,444,836,3236}; // 方式 3,分配空间的同时指定内容 int[] arr3 = neew int[5]{100,102,444,836,3236};
数组排序
选择排序
- 思路
首先在未排序数组中找到最小元素,存放到排序数组的其实位置,然后再从剩余未排序的元素中寻找最小的元素,放到排序数组起始位置,以此类推直到数组所有元素排序完毕;
- 实现
/** * 选择排序 * @param source 未排序数组 */ public void selectSort(int[] source){ // 数组长度 int size = source.lenth; for(int i = 0; i < size; i++){ for(int j = i + 1; j < size; j++){ // 进行交换,从小到大 if(source[i] > source[j]){ // 进行交换,从大到小 // if(source[i] < source[j]) int tmp = source[i]; source[i] = source[j]; source[j] = tmp; } } } }
冒泡排序
- 思路
通过双层循环,内层循环将相邻的两个数进行比较,将最大的一个数以冒泡(两两交换)的形式传送到数组尾部,每次将一个最大值传到数组尾部,外层循环则实现依次将当前最大值传送,最终实现排序;
- 实现
/** * 冒泡排序 * @param source 未排序数组 */ public void bubbleSort(int[] source){ // 数组长度 int size = source.length; for(int i = 0; i < size - 1; i++){ for(int j = 0; j < size - 1 - i; j++){ if(source[j] > source[j + 1]){ int tmp = source[j]; source[j] = source[j + 1]; source[j + 1] = tmp; } } } }
数组复制
数组一旦分配空间,就不再可变,当我们需要在原有数组的基础上增删改查时,则需要对数组进行复制;
- 将一个数组的值复制到另一个数组
/** * @param src 源数组 * @param srcPos 源数组要复制的起始位置 * @param dest 目的数组 * @param destPos 目的数组要放置的起始位置 * @param length 复制的长度 */ public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
- 合并数组
import java.util.Arrays; /** * Created with IntelliJ IDEA. * Version : 1.0 * Author : cunyu * Email : cunyu1024@foxmail.com * Website : https://cunyu1943.github.io * 公众号 : 村雨遥 * Date : 2020/5/6 上午10:58 * Project : mavenDemo * Package : PACKAGE_NAME * Class : MergeArr * Desc : 合并数组 */ public class MergeArr { public static void main(String[] args) throws Exception { int[] arr1 = {1, 5, 7, 9}; int[] arr2 = {0, 4, 11, 45}; int destSize = arr1.length + arr2.length; int[] mergeArr = new int[destSize]; merge(arr1, arr2, mergeArr); System.out.println(Arrays.toString(mergeArr)); } /** * 合并数组 * * @param arr1 源数组 1 * @param arr2 源数组 2 * @param destArr 合并后的数组 */ public static void merge(int[] arr1, int[] arr2, int[] destArr) { // 将数组 1 合并到最终数组 System.arraycopy(arr1, 0, destArr, 0, arr1.length); // 将数组 2 合并到最终数组 System.arraycopy(arr2, 0, destArr, arr1.length, arr2.length); } }
Arrays
方法 | 功能 |
copyOfRange |
数组复制 |
toString() |
转换为字符串 |
sort |
排序 |
binarySearch |
搜索 |
equals |
判断是否相同 |
fill |
填充 |
import java.util.Arrays; /** * Created with IntelliJ IDEA. * Version : 1.0 * Author : cunyu * Email : cunyu1024@foxmail.com * Website : https://cunyu1943.github.io * 公众号 : 村雨遥 * Date : 2020/5/6 下午1:27 * Project : mavenDemo * Package : PACKAGE_NAME * Class : ArraysOperation * Desc : Arrays 常见操作 */ public class ArraysOperation { public static void main(String[] args) throws Exception { int[] arr = {1, 9, 8, 49}; // 复制 int[] newArr = Arrays.copyOfRange(arr, 0, arr.length); // 转换为字符串 System.out.println(Arrays.toString(newArr)); // 排序 Arrays.sort(newArr); // 搜索 System.out.println(Arrays.binarySearch(newArr, 8)); // 比较是否相等 System.out.println(Arrays.equals(arr, newArr)); // 填充 Arrays.fill(arr, 10); System.out.println(Arrays.toString(arr)); } }
类和对象
继承
class Item{ String name; int price; } public class Armor extends Item{ int ac; public static void main(String[] args) { Armor a1 = new Armor(); Armor a2 = new Armor(); // 布甲相关属性 a1.name = "布甲"; a1.price = 300; a1.hjdj =15; // 锁子甲相关属性 a2.name = "锁子甲"; a2.price = 500; a2.hjdj =40; }
方法重载
**方法重载 ** 指方法名一样,但参数类型不一样;
构造方法
通过一个类构建一个对象的过程叫做 实例化,而实例化是通过 构造方法 来实现的;构造方法名和类名一样,但是 没有返回类型,默认会提够一个无参的构造方法,this
代表当前对象;
public class Hero{ String name; float hp; float armor; int moveSpeed; Hero(String name, float hp, float armor, int moveSpeed){ this.name = name; this.hp = hp; this.armor = armor; this.moveSpeed = moveSpeed; } }
访问修饰符
常用修饰符
符号 说明
private 私有
package/friendly/default 默认,
protected 受保护
public 公有
修饰符作用域
自身 同包子类 不同包子类 同包类 其他类
private 访问 不能继承 不能继承 无法访问 无法访问
package/friendly/default 访问 继承 不能继承 访问 无法访问
protected 访问 继承 继承 访问 无法访问
public 访问 继承 继承 访问 访问
修饰符使用场景
属性通常用 private 封装;
方法一般用 public 方便调用;
会被继承的方法,通常用 protected ;
package 使用较少;
原则:作用范围尽量小;
类属性
定义:当类中一个属性被 static 修饰时,叫做 类属性,也叫 静态属性,当一个属性被声明为类属性时,所有对象均共享一个值;
对象属性 :又叫 实例属性,非静态属性;
对象属性与类属性的对比 :
不同对象的 对象属性的值 都可能不一样,但所有对象的 类属性的值 都是一样的;
若一个属性对所有对象都不一样,则该属性应该设计为 对象属性,因为它 跟着对象走;
若一个对象被所有对象共享,均一样,则该属性应该被设计为 类属性;
访问方式
对象.类属性 :teemo.hp ;
类.类属性 :Hero.hp ,推荐使用;
类方法
类方法 :又叫做 静态方法,被 static 修饰的方法,访问类方法,无需对象 存在就可以直接访问,若某一方法中 未调用任何对象属性,则可以设计为类方法;
对象方法 :又叫 实例方法,非静态方法,访问一个对象方法,必须建立在 有一个对象 的前提上,若某一方法中 访问了对象属性,则该方法 必须 设计为对象方法;
类方法调用方式:
对象.类方法 :teemo.die() ;
类.类方法 :Hero.battleWin() ,推荐使用;
属性初始化
对象属性初始化方式 :
声明该属性时初始化;
构造方法中初始化;
初始化块;
public class Hero{ // 声明同时初始化 public String name = "teemo"; protected float hp; float maxHP; // 初始化块初始化 { maxHP = 999; } // 构造方法中初始化 public Hero(){ hp = 100; } }
类属性初始化方式 :
- 声明该属性时初始化;
- 静态初始化块;
public class Hero{ public String name; protected float hp; float maxHP; // 声明时初始化 public static int itemCapacity = 10; // 静态初始化块 static{ itemCapacity = 20; } }
属性初始化块的执行顺序:
静态初始化块 -> 非静态初始化块 ->构造方法 ;
单例模式
定义 : 又叫 Singleton 模式,指在一个类在 JVM 中,只存在一个实例;
单例模式分类:
饿汉式 : 无论如何都会创建一个实例,通过 public static 的 getInstance 方法获取一个对象,每次获取的都是同一个对象,属于 立即加载,无论是否用到该对象,均加载;
懒汉式 :只有在调用 getInstance 方法时才会创建实例,每次获取的都是同一个对象,属于 延迟加载,只有在使用该对象时才加载,同时具有 线程安全;
单例模式三要素 :
构造方法私有化 ;
静态属性指向实例 ;
public staic 的 getInstance 方法,**返回上一个要素中的静态属性 ** ;
/** * 饿汉式 */ public class Earth{ // 私有构造方法,使得无法在外部通过 new 实例化 private Earth(){ } // 定义类属性同时初始化 private static Earth instance = new Earth(); // private static 方法,用于获取对象 public static Earth getInstance(){ return instance; } public static void main(String[] args){ Earth earth1 = Earth.getInstance(); Earth earth2 = Earth.getInstance(); // true System.out.println(earth1 == earth2) } }
/** * 懒汉式 */ public class Earth{ // 私有构造方法,使得无法在外部通过 new 实例化 private Earth(){ } // 定义类属性 private static Earth instance; // private static 方法,用于获取对象 public static Earth getInstance(){ // instance 未指向任何对象,将其实例化 if(instance == null){ instance = new Earth(); } return instance; } public static void main(String[] args){ Earth earth1 = Earth.getInstance(); Earth earth2 = Earth.getInstance(); // true System.out.println(earth1 == earth2) } }
枚举类型
- 枚举是一种特殊的类,方便定义常量,一般都是全大写;
public enum Heros{ TANK, WIZARD, ASSASSIN, WARRIOR, ASSIST, RANGED, PUSH, FARMING } public class Demo{ public static void main(String[] args){ for(Heros hero : Heros.values()){ System.out.println(hero); } } }
接口与继承
接口
接口 无法用于实例化;
接口 无构造方法;
接口中的 方法均为抽象方法;
无法包含成员变量,除了 static 和 final 变量;
接口支持多继承;
对象转型
向上转型(子类转父类、实现类转接口)
Hero hero = new Hero();
AdHero ad = new AdHero();
hero = ad;
向下转型(父类转子类、接口转实现类)
Hero hero = new Hero();
AdHero ad = new AdHero();
ad = (AdHero)hero;
重写
子类可以继承父类对象方法,继承后重复提供该方法,则叫做 方法的重写,也叫覆写(override);
class Item{ String name; int price; public void buy(){ System.out.println("购买"); } public void effect(){ System.out.println("物品使用后生效"); } } public class LifePotion extends Item{ @override public void effect(){ System.out.println("血瓶使用后回血"); } }
多态
操作符的多态 :同一操作符在不同情景下具有不同作用,如 + 两侧是整形,则代表 数字相加;若其中任意一个是字符串,则代表 字符串连接;
类的多态需要具备的条件 :
父类(接口)引用指向子类对象 ;
调用的方法经历重写;
public interface Mortal{
public void die();
}
public class Hero{ public String name; protected float hp; public Hero(String name, float hp){ this.name = name; } public void kill(Mortal m){ m.die(); } public static void main(String[] args){ Hero hero = new Hero("赵云", 1000.0f); APHero ap = new APHero("安琪拉", 400.0f); ADHero ad = new ADHero("后羿", 450.0f); ADAPHero adap = new ADAPHero("嫦娥", 600.0f); hero.kill(ad); hero.kill(ap); hero.kill(adap); } }
public class ADHero extends Hero implements Mortal{ @override public void die(){ System.out.println("AD 被击杀"); } }
public class APHero extends Hero implements Mortal{ @override public void die(){ System.out.println("AP 被击杀"); } }
public class ADAPHero extends Hero implements Mortal{ @override public void die(){ System.out.println("ADAP 被击杀"); } }
隐藏
- 定义 :父类和子类拥有相同名字的属性或方法时,父类的同名属性或方法形式上不见了,但实际仍存在;即对于被隐藏的属性和方法,不会被覆盖,当父类引用指向子类对象时,调用的隐藏属性或方法仍然是父类的,而不会发生动态绑定;
public class Test { public static void main(String[] args) { Circle circle = new Circle();//本类引用指向本类对象 Shape shape = new Circle();//父类引用指向子类对象(会有隐藏和覆盖) System.out.println(circle.name); circle.printType(); circle.printName(); //以上都是调用Circle类的方法和引用 System.out.println(shape.name);//调用父类被隐藏的name属性 shape.printType();//调用子类printType的方法 shape.printName();//调用父类隐藏的printName方法 } } class Shape { public String name = "shape"; public Shape(){ System.out.println("shape constructor"); } public void printType() { System.out.println("this is shape"); } public static void printName() { System.out.println("shape"); } } class Circle extends Shape { public String name = "circle"; //父类属性被隐藏 public Circle() { System.out.println("circle constructor"); } //对父类实例方法的覆盖 public void printType() { System.out.println("this is circle"); } //对父类静态方法的隐藏 public static void printName() { System.out.println("circle"); } }
输入结果如下 :
shape constructor circle constructor circle this is circle circle shape this is circle shape
Object 类
toString()
所有类均继承自 Object ,所以所有类均有 toString() 方法,返回 当前对象的字符串表达 ;
finalize()
当一个对象没有任何引用指向的时候,就满足垃圾回收的条件,当被垃圾回收时,其 finalize() 方法就会 被虚拟机 JVM 调用,此时无需开发人员主动调用;
equals()
用于判断两个对象内容是否相同;
==
不属于 Object 类的方法,用于判断两个对象是否相同(即判断两个引用是否指向同一对象);
hashCode()
用于返回一个对象的哈希值;
getClass()
返回一个对象的 类对象,主要用于 反射机制;
final
修饰类 :final 修饰类时,表示当前类不允许继承;
修饰方法 :final 修饰方法时,表示该方法不允许被重写;
修饰基本类型变量 :final 修饰基本类型变量时,表示该变量只有一次赋值机会;
修饰引用 :final 修饰引用时,表示该引用只有一次指向对象的机会;
抽象类
定义:在类中声明一个方法,该方法无具体实现,是一个 “空” 方法,则该方法叫做抽象方法,用 abstract 修饰;而当一个类有抽象方法时,该类必须被声明为 抽象类,抽象类不能直接实例化;
接口与抽象类的区别 :
子类 可以实现多个接口,但只能继承一个抽象类;
抽象类可以定义 public、package、protected、private、静态和非静态属性、final 和非 final 属性,但 接口中声明的属性只能是 public、静态、final;
内部类
可以分为如下 4 类:
非静态内部类 :直接定义在一个类中,可以直接访问外部类的 private 属性,内部类实例化语法:内部类 对象名 = new 外部类().new 内部类();;
package charactor; public class Hero { private String name; // 姓名 float hp; // 血量 float armor; // 护甲 int moveSpeed; // 移动速度 // 非静态内部类,只有一个外部类对象存在的时候,才有意义 // 战斗成绩只有在一个英雄对象存在的时候才有意义 class BattleScore { int kill; int die; int assit; public void legendary() { if (kill >= 8) System.out.println(name + "超神!"); else System.out.println(name + "尚未超神!"); } } public static void main(String[] args) { Hero garen = new Hero(); garen.name = "盖伦"; // 实例化内部类 // BattleScore对象只有在一个英雄对象存在的时候才有意义 // 所以其实例化必须建立在一个外部类对象的基础之上 BattleScore score = garen.new BattleScore(); score.kill = 9; score.legendary(); } }
- 静态内部类 :在一个类中声明一个静态内部类,不能访问外部类的实例属性和方法,只能访问外部类私有静态成员,不需要一个外部类的实例为基础,可以直接实例化,语法如下:
外部类.静态内部类 对象名 = new 外部类.静态内部类();
package charactor; public class Hero { public String name; protected float hp; private static void battleWin(){ System.out.println("battle win"); } //敌方的水晶 static class EnemyCrystal{ int hp=5000; //如果水晶的血量为0,则宣布胜利 public void checkIfVictory(){ if(hp==0){ Hero.battleWin(); //静态内部类不能直接访问外部类的对象属性 System.out.println(name + " win this game"); } } } public static void main(String[] args) { //实例化静态内部类 Hero.EnemyCrystal crystal = new Hero.EnemyCrystal(); crystal.checkIfVictory(); } }
- 匿名类 :在 声明一个类的同时实例化,使用外部局部变量时,该变量必修修饰为
final
;
package charactor; public abstract class Hero { String name; //姓名 float hp; //血量 float armor; //护甲 int moveSpeed; //移动速度 public abstract void attack(); public static void main(String[] args) { ADHero adh=new ADHero(); //通过打印adh,可以看到adh这个对象属于ADHero类 adh.attack(); System.out.println(adh); Hero h = new Hero(){ //当场实现attack方法 public void attack() { System.out.println("新的进攻手段"); } }; h.attack(); //通过打印h,可以看到h这个对象属于Hero$1这么一个系统自动分配的类名 System.out.println(h); } }
- 本地类 :可以看作是 带名字的匿名类,匿名类不同之处在于内部类的是内部类必须声明在成员的位置,即与属性和方法平等位置,而本地类和匿名类一样,直接声明在代码块,可以是任何地方;
package charactor; public abstract class Hero { String name; //姓名 float hp; //血量 float armor; //护甲 int moveSpeed; //移动速度 public abstract void attack(); public static void main(String[] args) { //与匿名类的区别在于,本地类有了自定义的类名 class SomeHero extends Hero{ public void attack() { System.out.println( name+ " 新的进攻手段"); } } SomeHero h =new SomeHero(); h.name ="地卜师"; h.attack(); } }
- 练习
public abstract class Item{ public abstract void disposable(); public static void main(String[] args) throws Exception{ Item item = new Item(){ public void disposable(){ System.out.println("一次性"); } } } }
默认方法
默认方法自 JDK8
加入,指 接口中也可以加入具体方法(即默认方法,声明为 default
),而不仅限于抽象方法;
最后练习
public abstract class Animal{ protected int legs; protected Animal(int legs){ this.legs = legs; } public abstract void eat(); public void walk(int legs){ if(legs > 0){ System.out.println("用" + legs + "条腿走路") } } } class Spider extends Animal{ protected Spider(int legs){ super(legs); } @Override public void eat(){ System.out.println("蜘蛛吃东西"); } } public interface Pet{ String name; public void setName(String name); public String getName(); public void play(); } class Cat extends Animal implements Pet{ String name; protected Cat(String name){ super(4); this.name = name; } public Cat(){ this.name = ""; } @Override public void eat(){ System.out.println("猫在吃鱼"); } @Override public void setName(String name){ this.name = name; } @Override public String getName(){ return this.name; } @Overrid public void play(){ System.out.println("猫在玩毛线"); } } class Fish extends Animal implements Pet{ private String name; protected Fish(){ super(0); } @Override public void setName(String name){ this.name = name; } @Override public String getName(){ return this.name; } @Override public void walk(int legs){ System.out.println("鱼没有腿,只能游泳"); } @Override public void play(){ System.out.println("鱼在水力追蝌蚪"); } @Override public void eat(){ System.out.println("鱼吃草"); } }
数字与字符串
拆箱装箱
基本数据类型及对应封装类
自动装箱:无需调用构造方法,通过 = 自动把 基本类型转换为封装类 的过程叫做自动装箱;
自动拆箱 :无需调用对应方法,通过 = 自动将 封装类转换为基本类型 的过程叫做自动拆箱;
int 类型的最大最小值 : 最大值 :Integer.MAX_VALUE;最小值 :Integer.MIN_VALUE;
public class TestNumber{ public static void main(String[] args) throws Exception{ byte byteNum1 = 3; // 自动装箱 Byte byteNumClass1 = byteNum1; // 自动拆箱 Byte byteNumClass2 = new Byte(byteNum1); byte byteNum2 = byteNumClass2; } }
字符串转换
数字转字符串
- 使用
String
类的静态方法valueOf
; - 现将基本类型封装成对象,然后调用
toString
方法; - 通过
+
将数字与“”
相连;
public class Demo{ public void main(String[] args) throws Exception{ int num = 200; // 方法 1 String numString1 = String.valueOf(num); // 方法 2 Integer numClass = new Integer(num); String numString2 = numClass.toString(); // 方法 3 String numString3 = num + ""; } }
字符串转数字
- 通过各个封装类的静态方法
parseXxx
进行装换;
public class Demo{ public void main(String[] args) throws Exception{ String numString1 = "34"; int num1 = Integer.parseInt(numString1); String numString2 = "35.34"; float num2 = Float.parseFloat(numString2); } }
格式化输出
字符 | 含义 |
%s |
字符串 |
%d |
数字 |
%n |
换行(平台无关) |
public class TestNumber { public static void main(String[] args) { String name ="迦罗"; int kill = 8; String title="超神"; String sentenceFormat ="%s 在进行了连续 %d 次击杀后,获得了 %s 的称号%n"; // printf 和 format 效果一样 //使用printf格式化输出 System.out.printf(sentenceFormat,name,kill,title); //使用format格式化输出 System.out.format(sentenceFormat,name,kill,title); } }
- 换行符
DOS 和 Windows
中,每行结尾是\r\n
;Linux
中,每行结尾是\n
;Mac
中,每行结尾是\r
;
- 常用格式化方式
import java.util.Locale; public class TestNumber { public static void main(String[] args) throws Exception{ int year = 2020; //总长度,左对齐,补0,千位分隔符,小数点位数,本地化表达 //直接打印数字 System.out.format("%d%n",year); //总长度是8,默认右对齐 System.out.format("%8d%n",year); //总长度是8,左对齐 System.out.format("%-8d%n",year); //总长度是8,不够补0 System.out.format("%08d%n",year); //千位分隔符 System.out.format("%,8d%n",year*10000); //小数点位数 System.out.format("%.2f%n",Math.PI); //不同国家的千位分隔符 // 法国 System.out.format(Locale.FRANCE,"%,.2f%n",Math.PI*10000); // 美国 System.out.format(Locale.US,"%,.2f%n",Math.PI*10000); // 英国 System.out.format(Locale.UK,"%,.2f%n",Math.PI*10000); } }
字符串
- 创建字符串的方式
- 当有一个 字面值 出现时,虚拟机自动创建一个字符串;
- 调用
String
的构造方法创建; - 通过字符数组创建;
- 通过
+
进行字符串拼接;
public class TestString { public static void main(String[] args) { // 字面值创建 String garen ="盖伦"; // 构造方法创建 String teemo = new String("提莫"); // 通过字符数组创建 char[] cs = new char[]{'崔','斯','特'}; String hero = new String(cs); // 通过 + 加号进行字符串拼接 String hero3 = garen + teemo; } }
String 被 final 修饰,无法被继承,而且一旦被创建就不可改变(不能增加长度、不能减少长度、不能插入字符、不能删除字符、不能修改字符);
常见方法
方法 简介
charAt(int index) 获取某索引位置字符
toCharArray() 将字符串转换为字符数组
subString(int start, int end) 获取索引位置在 [start, end) 的子字符串
split(String str) 根据分割符将字符串分割为字符串数组
trim() 去掉首尾空格
toLowerCase() 全部变成小写
toUpperCase() 全部变成大写
indexOf 字符或子字符串第一次出现的索引位置
lastIndexOf 字符或子字符串最后一次出现的索引位置
contains 字符串是否包含子字符串
replaceAll 用指定字符串替换目标字符串
replaceFirst 用指定字符串替换第一个目标字符串
startsWith 判断字符串是否以子字符串开始
endsWith 判断字符串是否以子字符串结束
字符串比较
用 == 比较字符串是否指向同一对象,equals() 方法比较字符串内容是否一样;
注意特例 :
public class TestString { public static void main(String[] args) { String str1 = "the light"; String str2 = new String(str1); // 用于判断是否是同一个字符串对象 System.out.println( str1 == str2); // false // 用于判断是否是同一个字符串对象 System.out.println(str1.equals(str2)); // true // 特例,当编译器遇到字符串字面值时,若发现有重复的,则会直接使用而不再重复创建 String str3 = "the light"; System.out.println( str1 == str3); // true } }
StringBuffer
StringBuffer 不同于 String,属于可变长的字符串,需要经常操作字符串时,StringBuffer 性能更高,常用方法如下:
方法 功能
append 追加
delete 删除
insert 插入
reverse 反转
length 内容长度
capacity 总空间
public class TestString { public static void main(String[] args) { String str1 = "let there "; // 根据str1创建一个StringBuffer对象 StringBuffer sb = new StringBuffer(str1); //在最后追加 sb.append("be light"); System.out.println(sb); // 删除4-10之间的字符 sb.delete(4, 10); System.out.println(sb); // 在4这个位置插入 there sb.insert(4, "there "); System.out.println(sb); // 反转 sb.reverse(); System.out.println(sb); // 内容长度 System.out.println(sb.length()); // 总空间 System.out.println(sb.capacity()); } }
日期
日期格式化
SimpleDateFormat
类常用方法
方法 | 功能 |
format |
日期转字符串 |
parse |
字符串转日期 |
import java.text.SimpleDateFormat; import java.util.Date; /** * 日期转字符串 */ public class TestDate { public static void main(String[] args) throws Exception{ //y 代表年 //M 代表月 //d 代表日 //H 代表24进制的小时 //h 代表12进制的小时 //m 代表分钟 //s 代表秒 //S 代表毫秒 SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS" ); Date d= new Date(); String str = sdf.format(d); System.out.println("当前时间通过 yyyy-MM-dd HH:mm:ss SSS 格式化后的输出: "+str); SimpleDateFormat sdf1 =new SimpleDateFormat("yyyy-MM-dd" ); Date d1= new Date(); String str1 = sdf1.format(d1); System.out.println("当前时间通过 yyyy-MM-dd 格式化后的输出: "+str1); } }
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class TestDate { public static void main(String[] args) { SimpleDateFormat sdf =new SimpleDateFormat("yyyy/MM/dd HH:mm:ss" ); String str = "2020/5/1 12:12:12"; try { Date d = sdf.parse(str); System.out.printf("字符串 %s 通过格式 yyyy/MM/dd HH:mm:ss %n转换为日期对象: %s",str,d.toString()); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }