java基础

java的核心优势

  1. 跨平台/可移植性
  2. 安全性
  3. 面向对象
  4. 简单性
  5. 高性能
  6. 分布式
  7. 多线程
  8. 健壮性,不会造成计算机系统崩溃

JVM应用程序的运行机制

JVM JRE JDK 的区别

  1. JVM是一个虚拟的用于执行bytecode字节码的“虚拟计算机”
    java写完之后,编译成字节码,再把字节码喂给JVM,JVM和操作系统打交道
  2. JRE包含java虚拟机、库函数、运行java应用程序所必须的文件
  3. JDK包含JRE,以及增加编译器和调试器等用于程序开发的文件
    JDK包含JRE包含JVM

对象和类的关系

类是对象的模板,对象是类的抽象

栈 堆 方法区

栈里存放的是:存储堆中对象的引用,存储基本数据类型,方法调用时进栈、方法执行完退栈
堆里存放的是:创建的对象,数组
方法区在堆里(包含了常量池):存放静态变量,静态方法,字符串(在常量池里)

this的本质

this的本质为创建好的对象的地址
由于在构造方法调用前,对象已经创建。因此,在构造方法中也可以使用this代表“当前对象”

static关键字的说明

  1. static修饰的成员变量和方法,从属于类,普通变量和方法从属于对象。
  2. static修饰的成员方法,只能调用static修饰的成员方法和变量
  3. 非static修饰的成员方法,可以调用static修饰的成员方法和变量

静态初始化块

在类初始化的时候执行
在构造器之前执行

面向对象的三大特征

继承、封装、多态

继承要点

  1. 父类也叫超类、基类、派生类等
  2. 继承为单继承,接口可以多实现
  3. 子类继承父类,可以得到父类的全部属性和方法(除了父类的构造方法),但不见得可以直接访问(比如父类的私有属性和方法)
  4. 如果定义一个类时,没有调用extends,则它的父类是:java.lang.Ojbect

方法重写要点

  1. 方法名、形参列表相同
  2. 返回值类型和声明异常类型,子类小于等于父类
  3. 访问权限,子类大于父类

JDK提供的编译器、解释器

编译器:javac.exe
解释器:java.exe

super父类对象引用

  1. super是直接父类对象的引用。可以通过super来访问父类中被子类覆盖的方法或属性。
  2. 所有的子类,默认调用父类的构造方法。
  3. 无参构造方法默认加super();
  4. 有参构造方法的super()不会自己加上,如果想加,必须自己手动加上。

继承树追溯问题

封装作用:

  1. 提高代码的安全性
  2. 提高代码的复用性
  3. "高内聚":封装细节,便于修改内部代码,提高可维护性。
  4. "低耦合":简化外部调用,便于调用者使用,便于扩展和协作。

访问控制

修饰符 同一个类 同一个包 不同包的子类 所有类
private
default
protected
public

封装的使用细节

  1. 一般使用private访问权限。
  2. 提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,以提供对属性的赋值与读取操作
    (boolean变量的get方法是is开头)
  3. 一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法是public修饰。

JavaBean规则

  1. 无参构造函数
  2. getter/setter方法
  3. 属性私有化

多态

多态指同一个方法调用,由于对象不同可能会有不同的行为。

多态要点

  1. 多态是方法的多态
  2. 3个必要条件:继承,方法重写,父类引用指向子类对象
  3. 父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。

final关键字

作用:

  1. 修饰变量:被它修饰的变量不可改变
  2. 修饰方法:该方法不可被子类重写,但是可以重载
  3. 修饰类:修饰的类不能被继承

数组

声明:
int[] arr;
初始化:
1.默认初始化
int[] arr = new int[10];
2.静态初始化
int[] arr = {2, 1, 43, 123}
3.动态初始化
int[] arr = new int[2] arr[0] = 1; arr[1] = 2;

抽象类

使用要点:

  1. 有抽象方法的类只能定义成抽象类
  2. 抽象类不能实例化
  3. 抽象类可以包含属性、方法、构造方法,但是构造方法不能用来new实例,只能用来被子类调用。
  4. 抽象类只能用来被继承
  5. 抽象方法必须被子类实现
    抽象类的意义:
  6. 为子类提供统一的,规范的模板
  7. 子类必须实现相关的抽象方法

接口

  1. 只能是public默认
  2. 和类名采用相同的命名机制
  3. 接口可以多继承
  4. 接口中的属性只能是常量,总是:public static final修饰,不写也是
  5. 接口中的方法只能是:public abstract修饰。省略的话,也是。

内部类

  1. 成员内部类
  • 包含了静态内部类和非静态内部类
  • 可以使用private default protected public 任意进行修饰
  • 类文件:外部类$内部类.class
    非静态内部类
    1.非静态内部类必须即存在一个外部类对象里
    2.非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员
    3.非静态内部类不能有静态方法,静态属性和静态初始化块
public class TestInnerClass {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer().new Inner();
        inner.show();
    }
}

class Outer {
    private int age = 10;
    public void testOuter() {

    }

    class Inner {
        int age = 20;
        public void show() {
            int age = 30;
            System.out.println("外部类的成员变量age:"+Outer.this.age);
            System.out.println("内部类的成员变量age:"+this.age);
            System.out.println("成员变量age:"+age);
        }
    }
}

静态内部类

public class TestStaticInnerClass {
    public static void main(String[] args) {
        Outer2.Inner2 inner2 = new Outer2.Inner2();
    }
}

class  Outer2 {
    static class Inner2 {
        
    }
}
  1. 匿名内部类
    适合只需要使用一次的类
    注意:
  2. 匿名内部类没有访问修饰符
  3. 匿名内部类没有构造方法

  1. 局部内部类
public class TestPartClass {
    public void show() {
        // 作用域仅限于该方法
        class Inner {
            public void fun() {
                System.out.println("Helloworld");
            }
        }
        new Inner().fun();
    }
}

数组的拷贝

初始化多维数组

法一:
int[][] a = new int[3][];
a[0] = new int[]{20, 30};
a[1] = new int[]{10, 15, 80};
a[2] = new int[]{50, 60};

法二:
静态初始化二维数组
int[][] b = {
	{20, 30, 40}, 
	{50, 20},
	{100, 200, 300, 400}
}

包装类

基本数据类型 包装类
byte Byte
boolean Boolean
short Short
char Character
int Integer
long Long
float Float
double Double

包装类之间的相互转化

public class TestWrappedClass {
    public static void main(String[] args) {
        // 基本数据类型转成包装类对象
        Integer a = new Integer(3);
        Integer b = Integer.valueOf(30);
        System.out.println(a);
        System.out.println(b);


        // 把包装类对象转成基本数据类型
        int c = b.intValue();
        double d = b.doubleValue();

        // 把字符串转换成包装类对象
        Integer e = new Integer("123");
        System.out.println(e);
        Integer f = Integer.parseInt("999888");
        System.out.println(f);

        // 把包装类转换成字符串
        String str = f.toString();
        System.out.println(str);


        // 常见的常量
        System.out.println("int类型最大的整数"+Integer.MAX_VALUE);

        // 包装类提供了基本的数据类型和包装类和字符串之间的相互转化
    }
}

自动装箱和拆箱

自动装箱:基本类型的数据处于需要对象的环境中时,自动转为“对象”
自动拆箱:每当需要一个值时,对象会自动转成基本数据类型,没必要再去显示调用intValue()\ doubleValue()等转型方法。

Integer i = 100; // 自动装箱
// 相当于编译器自动为您做以下的语法
Integer i = Integer.valueOf(100); // 调用的是valueOf(100),
								//而不是new Integer(100);

// 自动拆箱
int b = a; // 编译器会修改成:int b = a.intValue();

// 自动拆箱
Integer c = null;
if (c != null) {
    int d = c; // 自动拆箱: 调用了:c.intValue();
}

缓存源码分析

缓存[-128, 127]之间的数字,实际就是系统初始的时候,创建了[-128, 127]之间的一个缓存数组。
当我们调用valueOf()的时候,首先检查是否在[-128, 127]之间,如果在这个范围则直接从缓存数组中拿出已经建好的对象。
如果不在这个范围,则创建新的Integer对象。

Integer in1 = Integer.valueOf(-128);
Integer in2 = -128;
System.out.println(in1 == in2); // true 因为-128在缓存范围内
System.out.println(in1.equals(in2)); // true

Integer in1 = Integer.valueOf(1234);
Integer in2 = 1234;
System.out.println(in1 == in2); // false 因为1234不在缓存范围内
System.out.println(in1.equals(in2)); // true

Date类的常见用法

1.1970年1月1日00:00:00定位基准时间,每个度量单位是毫秒
2.用long类型的变量来表示时间
long now = System.currentTimeMillis();
常见用法:(获取当前时间)

import java.util.Date;
public class TestDate {
    public static void main(String[] args) {
        Date date = new Date();
        System.out.println(date); // 获取当前时间
        // Tue Sep 07 17:54:03 CST 2021

        System.out.println(date.getTime()); // 1631008443198 指的是毫秒数

        Date date1 = new Date();
        System.out.println(date1.getTime()); // 1631008443228 指的是毫秒数

        System.out.println(date1.after(date)); // true
    }
}

DateFormat抽象类和SimpleDateForm实现类的使用

import java.util.Date;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;

public class TestDateFormat {
    public static void main(String[] args) throws ParseException {
        // 把时间对象按照"格式字符串指定的格式"转成相应的字符串
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String str = df.format(new Date(4000000));
        System.out.println(str);

        // 把字符串按照"格式字符串指定的格式"转成相应的时间对象
        DateFormat df2 = new SimpleDateFormat("yyyy年MM月dd日 hh时mm分ss秒");
        Date date = df2.parse("1982年01月11日 11时01分11秒");
        System.out.println(date);

        // 测试今天是今年的第多少天
        DateFormat df5 = new SimpleDateFormat("D");
        String d = df5.format(new Date());
        System.out.println(d);
    }
}

Calendar抽象类和GregorianCalendar实现类的使用

Calendar为我们提供了关于日期计算的相关功能,比如:年 月 日 时 分 秒的展示和计算
GregorianCalendar是Calendar的具体子类,提供了标准日历系统。

import sun.util.calendar.Gregorian;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

public class TestCalendar {
    public static void main(String[] args) {
        Calendar calendar = new GregorianCalendar(2000, 10, 10, 9, 19, 19);
        printCalendar(calendar);

        // 设置日期的相关元素
        Calendar c2 = new GregorianCalendar();
        c2.set(Calendar.YEAR, 8012);
        System.out.println(c2);

        // 日期的计算
        Calendar c3 = new GregorianCalendar();
        c3.add(Calendar.YEAR, 100);
        printCalendar(c3);

        // 日期对象和时间对象的转化
        Date d4 = c3.getTime(); // 把日期类转化为时间对象
        System.out.println(d4);
        Calendar c4 = new GregorianCalendar();
        c4.setTime(new Date()); // 把时间对象转为日期类
        printCalendar(c4);
    }
    public static void printCalendar(Calendar c) {
        int year = c.get(Calendar.YEAR);
        int date = c.get(Calendar.DAY_OF_MONTH);
        int month = c.get(Calendar.MONTH);
        int dayweek = c.get(Calendar.DAY_OF_WEEK) - 1;

        String dayweek2 = dayweek == 0?"日":dayweek + "";
        int hour = c.get(Calendar.HOUR);
        int minute = c.get(Calendar.MINUTE);
        int second = c.get(Calendar.SECOND);

        System.out.println(year+"年"+month+"月"+date+"日"+hour+"时"+minute+"分"+second+"秒"+"周"+dayweek2);
    }

}

日历程序

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
public class TestCalendar2 {
    public static void main(String[] args) throws ParseException {
        System.out.println("请输入日期(格式:2020-9-10)");
        Scanner scanner = new Scanner(System.in);
        String s = scanner.nextLine();
        DateFormat d = new SimpleDateFormat("yyyy-MM-dd");
        Date date1 = d.parse(s);

        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date1);
        int day = calendar.get(Calendar.DAY_OF_MONTH);

        System.out.println("日\t一\t二\t三\t四\t五\t六");
        calendar.set(Calendar.DAY_OF_MONTH, 1);

        int days = calendar.getActualMaximum(Calendar.DATE);
        for (int i = 0; i < calendar.get(Calendar.DAY_OF_WEEK) - 1; i++) {
            System.out.print("\t");
        }

        for (int i = 1; i <= days; i++) {
            if (i != day) {
                System.out.print(calendar.get(Calendar.DAY_OF_MONTH)+"\t");
            } else {
                System.out.print(calendar.get(Calendar.DAY_OF_MONTH) + "*" + "\t");
            }
            if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
                System.out.println();
            }

            calendar.add(Calendar.DAY_OF_MONTH,1);
        }

    }
}

Math类

Random类

枚举

注意:
1.当需要定义一组常量时,可以使用枚举类型
2.尽量不要使用枚举的高级特性,事实上高级特性都可以使用普通类来实现,没有必要引入枚举,加程序的复杂性。

enum Season {
    SPRING, SUMMER, AUTUMN, WINTER
}

public class TestEnum {
    public static void main(String[] args) {
        // 打印一个枚举中的类型
        System.out.println(Season.AUTUMN);

        Season a = Season.AUTUMN;

        // 应用枚举
        switch (a) {
            case SPRING: {
                System.out.println("春天。。。");
                break;
            }
            case SUMMER: {
                System.out.println("夏天。。。");
                break;
            }
            case AUTUMN: {
                System.out.println("秋天。。。");
                break;
            }
            case WINTER: {
                System.out.println("冬天。。。");
                break;
            }
        }
    }
}

异常

当继承的是RuntimeException时,可以直接抛,即写为throw new IllegalAgeException("年龄不能为负数");
自定义异常

public class test04 {
    public static void main(String[] args) {
        Person p = new Person();
        p.setAge(-10);
    }
}

class Person {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age == 0) {
            throw new IllegalAgeException("年龄不能为负数");
        }
        this.age = age;
    }
}

class IllegalAgeException extends RuntimeException {
    // 需要一个空构造器
    public IllegalAgeException() {

    }

    public IllegalAgeException(String msg) {
        super(msg);
    }
}

当继承的是Exception时,不可以直接抛,因为是编译器异常,而不是运行期异常。
即写为:

public void setAge(int age) {
	if (age == 0) {
		try {
			throw new IllegalAgeException("年龄不能为负数");
		} catch (IllegalAgeException e) {
			e.printStackTrace();
		}
	}
    this.age = age;
}

public void setAge(int age) throws IllegalAgeException {
	throw new IllegalAgeException("年龄不能为负数");
}
posted @ 2022-02-28 14:41  jsqup  阅读(32)  评论(0编辑  收藏  举报