文章目录
类变量(静态变量)
当需要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量
类变量是该类所有对象共享的,而实例变量是每个对象独享的
加上static称为类变量或静态变量,否则称为实例变量
类变量可以通过类名.类变量名或者对象名.类变量名(前提是满足访问修饰符的访问权限和范围)(类变量是随着类的加载而创建,所以即使没有创建对象实例也可以访问)
类变量的生命周期是随类的加载开始,随类消亡而销毁
类方法 和类变量使用类似
类方法中无this的参数,普通方法可以用
类方法中,只能访问静态变量或静态方法
普通方法,可以访问静态和普通成员(变量和方法)
调用顺序
创建一个子类对象时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:
1)父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
2)子类的静态代码块和静态属性(优先级一样,按定义顺序执行)
3)父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
4)父类的构造方法
5)子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
6)子类的构造方法
单例设计模型 单例(单个的实例)
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
单例模式有两种方式:饿汉式、懒汉式
两者主要的区别在于创建对象的时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建
饿汉式不存在线程安全问题,懒汉式存在
饿汉式存在浪费资源的可能
final关键字 (有以下需求时,会使用到final)
当不希望类被继承时,可以用final修饰
当不希望父类的某个方法被子类覆盖/重写时,可使用
当不希望类的某个属性的值被修改时
当不希望某个局部变量被修改时
package interface_;
/**
* 继承的价值主要在于解决代码的复用性和可维护性
* 接口的价值主要在于:设计(设计好各种规范[方法],让其他类去实现这些方法)
* 接口满足like - a 关系 继承满足 is - a 关系
*
/
public class ExtendsVsInterface {
public static void main(String[] args) {
LittleMonkey titty = new LittleMonkey("titty");
titty.climbing();
titty.swimming();
titty.flying();
}
}
interface Fishable{
void swimming();
}
interface Birdable{
void flying();
}
class Monkey{
private String name;
public Monkey(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void climbing(){
System.out.println("猴子会爬树");
}
}
class LittleMonkey extends Monkey implements Fishable, Birdable{
public LittleMonkey(String name) {
super(name);
}
@Override
public void swimming() {
System.out.println(getName() + " is swimming");
}
@Override
public void flying() {
System.out.println(getName() + " is flying");
}
}
package interface_;
/**
*
* 多态数组
*/
public class InterfacePolyArr {
public static void main(String[] args) {
// 接口类型数组
Usb[] usbs = new Usb[2];
usbs[0] = new Camera_();
usbs[1] = new Phone_();
for (int i = 0; i < usbs.length; i++) {
if (usbs[i] instanceof Phone_){ // 判断运行类型是Phone_
((Phone_) usbs[i]).call();
}
usbs[i].work();
}
}
}
interface Usb{
void work();
}
class Phone_ implements Usb{
@Override
public void work() {
System.out.println("phone is working");
}
public void call(){
System.out.println("calling");
}
}
class Camera_ implements Usb{
@Override
public void work() {
System.out.println("camera is working");
}
}
内部类
内部类:一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class),内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。
类的五大成员:属性、方法、构造器、代码块、内部类
package innerclass;
/**
*
* 局部内部类的使用
*/
public class LocalInnerClass {
public static void main(String[] args) {
Outer02 outer02 = new Outer02();
outer02.m1();
}
}
class Outer02{
private int n1 = 100;
private void m2(){
System.out.println("m2");
}
public void m1(){
// 1. 局部内部类是定义在外部类的局部位置,通常在方法
class Inner02{ // 局部内部类
// 2. 可以直接访问外部类的所有成员,包括私有的
// 3. 局部内部类不能添加访问修饰符,但是可以使用final修饰
// 4. 作用域:仅仅在定义它的方法或代码块中
public void f1(){
System.out.println("n1 = " + n1);
m2();
}
}
// 5. 外部类在方法中,可以创建内部类对象,然后调用方法即可
Inner02 inner02 = new Inner02();
inner02.f1();
}
}
匿名内部类,同时是一个对象
package innerclass;
/**
*
* 匿名内部类
*/
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04{
private int n1 = 10;
public void method(){
// 基于接口的匿名内部类
// ana的编译类型是IA(等号左边)
// ana的运行类型是匿名内部类
/*
实际上底层会分配类名Outer04$1 外部类名+$
class Outer04$1 implements IA{
@Override
public void cry() {
System.out.println("anonymous");
}
}
jdk底层创建匿名内部类,然后立马创建对象实例,并且把地址返回给ana
匿名内部类使用一次就不能再使用 (ana是个对象,可以继续使用)
*/
IA ana = new IA(){
@Override
public void cry() {
System.out.println("anonymous");
}
};
ana.cry();
/**
* 基于类的匿名内部类
*/
/*
1. father的编译类型 Father(等号左边)
2. father的运行类型 Outer04$2 注意后面带了花括号 是匿名内部类 new Father("jack"){};
*/
Father father = new Father("jack"){
};
System.out.println("father对象的运行类型 = " + father.getClass());
}
}
interface IA{
public void cry();
}
class Father{
public Father(String name){
}
public void test(){
}
}
枚举类
- 自定义枚举类
package enum_;
/**
* 自定义枚举类有一下特点:
* 1)构造器私有化
* 2)本类内部创建一组对象
* 3)对外暴露对象(通过为对象添加public final static修饰符)
* 4)可以提供get方法,但是不要提供set方法
*
/
public class Enumeration01 {
public static void main(String[] args) {
/**
* 实现枚举的方式:1)自定义类实现枚举 2)使用enum关键字实现枚举
*/
System.out.println(Season.AUTUMN);
System.out.println(Season.SPRING);
}
}
class Season{
private String name;
private String desc;
// 1. 讲构造器私有化,防止直接 new 对象
// 2. 去掉setXX相关方法,防止属性被修改
// 3. 在Season内部,直接创建固定的类
// 4. 优化,可以加入final修饰符 final
// 5. 枚举对象名通常使用全部大写,常量的命名规范
// 6. 对枚举对象/属性使用final+static共同修饰,实现底层优化
public final static Season SPRING = new Season("春天", "温暖");
public final static Season WINTER = new Season("冬天", "寒冷");
public final static Season SUMMER = new Season("夏天", "炎热");
public final static Season AUTUMN = new Season("秋天", "凉爽");
private Season(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
}
package enum_;
public class Enumeration01 {
public static void main(String[] args) {
/**
* 实现枚举的方式:1)自定义类实现枚举 2)使用enum关键字实现枚举
*/
System.out.println(Season.AUTUMN);
System.out.println(Season.SPRING);
}
}
enum Season{
/**
*
* 使用关键字enum来实现枚举类
* 1. 使用enum替代class
* 2. 直接对象名(实参列表)
* 3. 如果有多个对象,使用逗号间隔
* 4. 如果使用enum来实现枚举,要求讲定义的对象写在前面
* 5. 使用 enum 关键字开发一个枚举类时,默认会继承 Enum 类,因此可以使用继承的一些方法
*/
SPRING("春天", "温暖"), AUTUMN("秋天", "凉爽"); // 实参列表对应构造器的参数
private String name;
private String desc;
private Season(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
}
package enum_;
/**
*
* 使用关键字enum关键字后,就不能再继承其他类了,因为enum会隐式继承Enum
* 枚举类和普通类一样,可以实现接口
*/
public class EnumTest {
public static void main(String[] args) {
Week[] weeks = Week.values();
for (Week week: weeks){ //增强for循环, 取出weeks里面的每一个元素给week,然后输出
System.out.println(week);
}
}
}
enum Week{
MON("星期一"), TUES("星期二"), WED("星期三");
private String name;
private Week(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
异常
快捷键 ctrl+alt+T 选择try catch
异常分为两大类,运行时异常和编译时异常
package exception_;
public class Exception01 {
public static void main(String[] args) {
int num1 = 10;
int num2 = 0;
try {
int res = num1 / num2;
} catch (Exception e) {
// throw new RuntimeException(e);
System.out.println(e.getMessage());
// 输出异常信息
}
System.out.println("程序继续运行");
}
}
异常体系图
- NullPointException 空指针异常
package exception_;
public class NullPointException_ {
public static void main(String[] args) {
String name = null;
System.out.println(name.length());
}
}
- ArithmeticException 数学运算异常
- ArrayIndexOutOfBoundsException 数组下标越界异常
- ClassCastException 类型转换异常
class ClassCastException_ {
public static void main(String[] args) {
A b = new B(); // 向上转型
B b2 = (B)b; // 向下转型
C c2 = (C)b; // 会报错,B和C本身没有什么关系
}
}
- NumberFormatException 数字格式不正确异常[]
class NumberFormatException_{
public static void main(String[] args) {
String name = "as";
int num = Integer.parseInt(name); // 报错,无法转成整数
}
}
异常处理的方式
- try-catch-finally:程序员在代码中捕获的异常,自行处理 (finally也可以不写)
其中,finally代码块中,不论try代码块是否有异常发生,始终要执行finally (通常将释放资源的代码放在finally里面) - throws:讲发生的异常抛出,交给调用者(方法)处理,最顶级的处理者就是JVM
throws处理机制
(发生异常,要么try-catch-finally捕获异常自行处理,要么throws给上一级处理,最高级是JVM;JVM处理异常:1)输出异常信息 2)退出程序)
如果程序员没有显式的处理异常,默认throws
try-catch-finally
class Exception02{
public static int method(){
try {
String[] names = new String[3];
if (names[1].equals("tom")){ // 初始化指针没有赋值,这里会出现空指针异常
System.out.println(names[1]);
}else {
names[3] = "mango";
}
return 1;
}
catch (ArrayIndexOutOfBoundsException e){
return 2;
}
catch (NullPointerException e){ // 捕获到空指针异常 但是并不会在这里return 结束,因为有finally,finally是一定要执行的
return 3;
}
finally {
return 4; // 调到这里return 4结束
}
}
public static void main(String[] args) {
System.out.println(method());
}
}
/**
* 和上一题差不多,注意catch语句是执行的,只是不返回,到了finally才return
*/
class Exception02{
public static int method(){
int i = 1;
try {
i++;
String[] names = new String[3];
if (names[1].equals("tom")){ // 初始化指针没有赋值,这里会出现空指针异常
System.out.println(names[1]);
}else {
names[3] = "mango";
}
return 1;
}
catch (ArrayIndexOutOfBoundsException e){
return 2;
}
catch (NullPointerException e){ // 捕获到空指针异常 这里虽然return,但是++i的语句会执行
return ++i;
}
finally {
return ++i; // return 4结束
}
}
public static void main(String[] args) {
System.out.println(method());
}
}
/**
* finally里面如果没有return,catch语句里的变量先临时存放,然后执行finally,执行完finally里的语句,再回到catch里的return结束
*/
class Exception02{
public static int method(){
int i = 1;
try {
i++;
String[] names = new String[3];
if (names[1].equals("tom")){ // 初始化指针没有赋值,这里会出现空指针异常
System.out.println(names[1]);
}else {
names[3] = "mango";
}
return 1;
}
catch (ArrayIndexOutOfBoundsException e){
return 2;
}
catch (NullPointerException e){ // 捕获到空指针异常 执行i++,结果i=3,注意并不return,要去执行finally,同时将此时的i存储给临时变量temp保存
return ++i;
}
finally {
++i;
System.out.println("i = " +i); // 执行++i,输出语句,但是并没有return,输出语句之后再回到上面catch执行return
}
}
public static void main(String[] args) {
System.out.println(method()); // 最后结果 i = 4,3
}
}
练习
/**
*
* 如果用户输入的不是一个整数,就提示他反复输入,直到输入一个整数为止
*/
class TryCatchExercise01{
public static void main(String[] args) {
boolean loop = true;
do {
Scanner num = new Scanner(System.in);
String i = num.next();
try {
int num1 = Integer.parseInt(i);
loop = false;
}catch (NumberFormatException e){
System.out.println("重新输入");
}
}while (loop);
}
}
throws
package exception_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class Throws01 {
public static void main(String[] args) {
}
public void f2() throws Exception, NullPointerException, ArithmeticException { // 这里throws后可以是FileNotFoundException也可以是其父类Exception,也可以是多个异常
/**
* 创建一个文件流对象
* 1. 这里的异常是一个FileNotFoundException编译异常
* 2. 使用throws,抛出异常,让调用f2方法的调用者(方法)处理 也可以使用try-catch-finally
* 3. throws后面的异常类型可以是方法中产生的异常,也可以是它的父类
* 4. throws关键字后也可以是异常列表,即可以抛出多个异常
*/
FileInputStream fls = new FileInputStream("d://aa.txt");
}
}
补充:
- 对于编译异常,程序必须处理,比如try-catch或者throws
- 对于运行时异常,程序中如果没有处理,默认是throws的方式处理
自定义异常
当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。
package exception_;
import java.util.Scanner;
public class CustomException {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("enter your age:");
int age = scanner.nextInt();
// 要求范围在 18-120 之间,否则抛出一个自定义异常
if (!(age >= 18 && age <=120)){
throw new AgeException("年龄需要在18-120之间");
}
System.out.println("年龄在要求范围内");
}
}
/**
*
* 一般情况下,自定义异常是继承RuntimeException,
* 即把自定义异常做成运行时异常,好处是可以使用默认的处理机制
*/
class AgeException extends RuntimeException{
public AgeException(String message) { // 构造器
super(message);
}
}
项目 | 意义 | 位置 | 后面跟的东西 |
---|---|---|---|
throws | 异常处理的一种方式 | 方法声明处 | 异常类型 |
throw | 手动生成异常对象的关键字 | 方法体中 | 异常对象 |
如
if (!(age >= 18 && age <=120)){
throw new AgeException("年龄需要在18-120之间");
}
异常练习
package exception_;
import java.sql.Array;
import java.util.Scanner;
public class Homework01 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String n11 = scanner.next();
String n22 = scanner.next();
try {
// 把接收到的参数,转为整数
int n1 = Integer.parseInt(n11);
int n2 = Integer.parseInt(n22);
double res = cal(n1, n2); // 该方法可能抛出ArithmeticException
System.out.println("计算结果是 = " + res);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println(e.getMessage());
}catch (NumberFormatException e){
System.out.println("参数格式不正确,需要输入整数");
}catch (ArithmeticException e){
System.out.println("出现了除0的异常");
}
}
public static double cal(int a, int b){
return a / b;
}
}
包装类
- 包装类和基本数据类型的转换
package wrapper_;
public class Integer01 {
public static void main(String[] args) {
// 装箱:基本类型->包装类型 反之,拆箱
// jdk5之后,就可以自动装箱和自动拆箱
// 自动装箱 int->Integer
int n2 = 200;
Integer integer = n2; // 底层使用的是Integer.valueOf(n2)
// 自动拆箱 Integer->int
int n3 = integer; // 底层使用的是 intValue()
// 其他包装类的用法类似
}
}
- 包装类方法
package wrapper_;
public class WrapperVSString {
public static void main(String[] args) {
// 包装类(以Integer为例)-> String
Integer i = 100; //自动装箱
// 方式1
String str1 = i + "";
// 方式2
String str2 = i.toString();
// 方式3
String str3 = String.valueOf(i);
// String -> 包装类(以Integer为例)
String str4 = "12345";
Integer i2 = Integer.parseInt(str4);
Integer i3 = new Integer(str4); // 构造器
}
}
String类
- String类实现了接口Serializable 【String可以串行化:可以在网络传输】
- String类实现了接口Comparable【String对象可以比较大小】
- String是final类,不能被其他的类继承
- String有属性 private final char value[]; 用于存放字符串的内容
- 要注意value是final类型,value不可以指向新的地址,但是单个字符的内容是可以变化的
StringBuffer
package string_;
public class StringBufferExercise01 {
public static void main(String[] args) {
String str = null;
StringBuffer sb = new StringBuffer();
sb.append(str); // 看底层源码,底层调用的是AbstractBuilder的appendNull,即把str=null,把null拆成单个字符进行append
System.out.println(sb.length()); // 4
System.out.println(sb); // null
StringBuffer sb1 = new StringBuffer(str); // 底层源码 super(str.length()+16); 而str是null,因此这里会抛出空指针异常
System.out.println(sb1);
}
}
public class StringBufferExercise02 {
public static void main(String[] args) {
String price = "13563564.56";
StringBuffer sb = new StringBuffer(price);
// for循环,每三位插入一个逗号
for (int i = sb.lastIndexOf(".")-3; i >0 ; i -= 3) {
sb = sb.insert(i, ",");
}
System.out.println(sb);
}
}
StringBuilder
- 是一个可变的字符序列,此类提供一个与StringBuffer兼容的API,但不保证同步。此类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,比StringBuffer要快
- 在StringBuilder上的主要操作是append和insert方法,可重载这些方法,以接收任意类型的数据
package string_;
public class StringBuilder01 {
public static void main(String[] args) {
/**
*
* 1. StringBuilder继承AbstractStringBuilder类
* 2. 实现了Serializable,说明StringBuilder对象可以串行化(对象可以在网络传输,可以保存到文件)
* 3. StringBuilder是final类,不能被继承
* 4. StringBuilder对象字符序列仍然是存放在其父类AbstractStringBuilder的char[] value,因此字符序列是在堆中
* 5. StringBuilder的方法,没有做互斥的处理,即没有synchronized关键字,因此在单线程的情况下使用
*/
StringBuilder stringBuilder = new StringBuilder();
}
}
String、StringBuffer和StringBuilder的比较
- StringBuffer和StringBuilder非常类似,均代表可变的字符序列,而且方法也一样
- String:不可变字符序列,效率低,但是复用率高
- StringBuffer:可变字符序列、效率较高(增删)、线程安全
- StringBuilder:可变字符序列、效率最高、线程不安全
String、StringBuffer和StringBuilder的使用
- 如果字符串存在大量的修改操作,一般使用StringBuffer或StringBuilder
- 如果字符串存在大量的修改操作,并在单线程的情况,使用StringBuilder
- 如果字符串存在大量的修改操作,并在多线程的情况,使用StringBuffer
- 如果自妇产很少修改,被多个对象引用,使用String,如配置信息等
Math类
Arrays
package arrays_;
import java.util.Arrays;
public class ArraysMethod01 {
/**
* Arrays里面包含了一系列静态方法,用于管理或操作数组
*/
public static void main(String[] args) {
Integer[] integers = {1, 10, 34, 45};
// 遍历数组
// toString返回数组的字符串形式
System.out.println(Arrays.toString(integers));
// sort排序
Integer arr[] = {1, -1, 3, 6, -92};
// 可以直接使用冒泡排序,也可以直接使用Arrays提供的sort方法排序
// 因为数组是引用类型,所以通过sort排序后,会直接影响到实参arr
Arrays.sort(arr); // 使用sort方法进行排序,然后再使用toString方法输出数组元素
System.out.println(Arrays.toString(arr));
}
}
package arrays_;
import java.util.Arrays;
import java.util.Comparator;
public class ArraysMethod01 {
public static void main(String[] args) {
// 定制排序
Integer arr[] = {1, -1, 3, 6, -92};
// 3. sort是重载的,也可以通过传入一个接口Comparator实现定制排序
// 4. 调用定制排序时,传入两个参数 1)排序的数组arr 2)实现了Comparator接口的匿名内部类,要求实现compare方法
// 5. 这里体现了接口编程的方式
Arrays.sort(arr, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Integer i1 = (Integer) o1;
Integer i2 = (Integer) o2;
return i2 - i1;
}
});
System.out.println(Arrays.toString(arr));
}
}
冒泡+定制排序
package arrays_;
import java.util.Arrays;
import java.util.Comparator;
public class ArraysSortCustom {
public static void main(String[] args) {
int[] arr = {1, -1, 8, 0, 20};
bubble01(arr);
System.out.println(Arrays.toString(arr));
bubble02(arr, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
int i1 = (Integer) o1;
int i2 = (Integer) o2;
return i1 - i2;
}
});
}
public static void bubble01(int[] arr) {
int temp = 0;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
// 从小到大
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
// 结合冒泡+定制
public static void bubble02(int[] arr, Comparator c) {
int temp = 0;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
// 从小到大
// 看这里的compare方法具体实现,实现在上面匿名内部类重写,也就是自定义规则
if (c.compare(arr[j], arr[j + 1]) > 0) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
}
二分查找
package arrays_;
import java.util.Arrays;
public class ArraysMethod02 {
public static void main(String[] args) {
Integer[] arr = {1, 2, 90, 123, 567};
// binarySearch 通过二分搜索法进行查找,要求该数组是有序的
int index = Arrays.binarySearch(arr, 134); // 如果找不到,return -(low + 1),即应该在的位置索引+1,再取负号
System.out.println(index); // -5
}
}
数组元素的复制 copyOf
Integer[] newArr = Arrays.copyOf(arr, arr.length);
// 从arr数组,拷贝arr.length个元素到newArr数组中
// 如果拷贝的长度 > arr.length,就在新数组后面增加null,如果拷贝长度<0,则返回异常
数组元素的填充
package arrays_;
import java.util.Arrays;
public class ArraysMethod02 {
public static void main(String[] args) {
Integer[] num = new Integer[]{9, 3, 2};
Arrays.fill(num, 99); // 使用99来填充数组
System.out.println(Arrays.toString(num)); // [99, 99, 99]
}
}
练习
package arrays_;
import java.util.Arrays;
import java.util.Comparator;
public class ArrayExercise {
/**
* 自定义Book类,里面包含name和price,按price排序(由大到小)。
* 要求使用两种方式排序,有一个Book[] books = 4本书对象
* <p>
* 使用前面学习过的传递实现Comparator接口匿名内部类
* 按照price(1)从小到大(2)从大到小
* (3)按照书名长度从大到小
*/
public static void main(String[] args) {
Book[] books = new Book[4];
books[0] = new Book("红楼梦", 100);
books[1] = new Book("金瓶梅新", 90);
books[2] = new Book("青年文摘20年", 5);
books[3] = new Book("java从入门到放弃", 300);
System.out.println(Arrays.toString(books));
Arrays.sort(books, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Book book1 = (Book) o1;
Book book2 = (Book) o2;
double price_minus = book2.getPrice() - book1.getPrice();
if (price_minus > 0){
return -1;
}
else if (price_minus < 0){
return 1
}
else {
return 0;
}
}
});
System.out.println(Arrays.toString(books));
}
}
class Book {
private String name;
private double price;
public Book(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
System
class System_{
public static void main(String[] args) {
// exit 退出当前程序
System.out.println("ok1");
// exit(0)表示程序退出
// 0表示一个状态,正常退出
System.exit(0);
System.out.println("ok2");
}
}
class System_{
public static void main(String[] args) {
// System.currentTimeMillis()
System.out.println(System.currentTimeMillis());
}
}
大数处理方案
- BigInteger和BigDecimal
1)BigInteger适合保存比较大的整型
2)BigDecimal适合保存精度更高的浮点数(小数)
注意,BigInteger和BigDecimal做加减乘数有指定方法,而不是直接+ - x /
日期类
第一代日期类
- Date:精确到秒,代表特定的瞬间
- SimpleDateFormat:格式和解析日期的类
SimpleDateFormat格式化和解析日期的具体类,它允许进行格式化(日期->文本)、解析(文本->日期)和规范化
package date_;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Date01 {
public static void main(String[] args) {
Date d1 = new Date(); // 获取当前系统的时间
// 默认输出的日期格式时国外的方式,因此通常需要对格式进行转换
// 创建SimpleDateFormat对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
String format = sdf.format(d1);
System.out.println(format);
}
}
package date_;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Date01 {
public static void main(String[] args) throws ParseException {
Date d1 = new Date(); // 获取当前系统的时间
// 默认输出的日期格式时国外的方式,因此通常需要对格式进行转换
// 创建SimpleDateFormat对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
String format = sdf.format(d1);
System.out.println(format);
System.out.println("==================");
// 还可以通过指定毫秒数得到时间
Date d2 = new Date(923456);
System.out.println(d2); // Thu Jan 01 08:15:23 CST 1970
System.out.println(d1.getTime()); // 获取某个时间对应的毫秒数
System.out.println("================================");
// 可以把一个格式化的String转换成对应的Date
// 在把String->Date,使用sdf格式需要和给的String的格式一样,否则会抛出转换异常
String s = "1996年01月01日 10:20:30 星期一";
Date parse = sdf.parse(s);
System.out.println(parse); // Mon Jan 01 10:20:30 CST 1996
}
}
第二代日期类
- 第二代日期类,主要就是Calendar类
- Calendar类是一个抽象类,它为特定瞬间与一组诸如YEAR、 MONTH、 DAY_OF_MONTH、 HOUR等日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。
package date_;
import java.util.Calendar;
public class Calendar_ {
/**
* Calendar是一个抽象类,并且构造器是private
* 可以通过getInstance()来获取实例
* 提供大量的方法和字段给程序员
*/
public static void main(String[] args) {
Calendar c = Calendar.getInstance();
System.out.println(c);
// 获取日历对象的某个日历字段
System.out.println("year: " + c.get(Calendar.YEAR));
// 注意这里月份+1,因为Calendar返回月份的时候,是按照0开始编号的
System.out.println("month: " + c.get(Calendar.MONTH) + 1);
// Calendar没有提供对应的格式化的类,因此需要程序员自己组合来输出
System.out.println(c.get(Calendar.YEAR) + "-" +c.get(Calendar.MONTH) + "-" + c.get(Calendar.DAY_OF_MONTH));
// Calendar.HOUR 是按照12小时进制输出的;如果需要按照24小时进制来获取时间,改为Calendar.HOUR_OF_DAY
}
}
第三类日期类
- 常见方法
1)LocalDate:只包含日期,可以获取日期字段
2)LocalTime:只包含时间,可以获取时间字段
3)LocalDateTime:包含日期+时间,可以获取日期和时间字段
package date_;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class LocalDate_ {
public static void main(String[] args) {
/**
* 第三代日期
*/
// 1. 使用now()返回表示当前日期时间的对象
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);
System.out.println("year = " + ldt.getYear());
// 2. 使用DateTimeFormatter对象来进行格式化
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String format = dateTimeFormatter.format(ldt);
System.out.println(format);
}
}
练习:字符串指定部分进行反转
package date_;
import java.util.Arrays;
/**
*
* 将字符串中指定部分进行反转
*/
public class Homework01 {
public static void main(String[] args) {
String s = "abcdefy";
System.out.println(s);
try {
System.out.println(reverse(s,4, 2303));
} catch (Exception e) {
System.out.println(e.getMessage());
return;
}
}
public static String reverse(String str, int start, int end) {
// 对输入的参数做一个验证
/**
* 小技巧:写成正确的情况,再取反即可
*/
if (!(str != null && start >= 0 && end > start && end <str.length())){
throw new RuntimeException("参数不正确");
}
char[] chars = str.toCharArray();
char t = ' ';
for (int i = start, j = end; i < j; i++, j--) {
t = chars[i];
chars[i] = chars[j];
chars[j] = t;
}
// 使用chars重新构建一个String 返回
return new String(chars);
}
}
邮箱验证(并不严谨,但是逻辑思维可借鉴)
package date_;
import java.util.Scanner;
public class Homework03 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String user_name = scanner.next();
String pwd = scanner.next();
String email = scanner.next();
try {
userRegister(user_name, pwd, email);
System.out.println("注册成功");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static void userRegister(String name, String pwd, String email){
// 额外的校验
if (!(name != null && pwd != null && email != null)){
throw new RuntimeException("参数不为空");
}
// 第一个条件校验
int userLength = name.length();
if (!(userLength >= 2 && userLength <= 4)){
throw new RuntimeException("用户名长度为2~4");
}
// 第二个条件校验
if (!(pwd.length() == 6 && isDigital(pwd))){
throw new RuntimeException("密码长度为6,要求全为数字");
}
// 第三个条件校验
int i = email.indexOf('@');
int j = email.indexOf('.');
if (!(i > 0 && j > i)){
throw new RuntimeException("邮箱不符合要求");
}
}
public static boolean isDigital(String str){
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (chars[i] < '0' || chars[i] > '9'){
return false;
}
}
return true;
}
}
按指定格式输出字符串
String.format的使用
package date_;
public class Homework05 {
public static void main(String[] args) {
String name = "Willian Jefferson Clinton";
printName(name);
}
public static void printName(String str){
if (str == null) {
System.out.println("str 不能为空");
return;
}
String[] names = str.split(" ");
if (names.length != 3){
System.out.println("输入的字符格式不对");
return;
}
String format = String.format("%s,%s .%c", names[2], names[1], names[1].toUpperCase().charAt(0));
System.out.println(format);
}
}