java基础
java的核心优势
- 跨平台/可移植性
- 安全性
- 面向对象
- 简单性
- 高性能
- 分布式
- 多线程
- 健壮性,不会造成计算机系统崩溃
JVM应用程序的运行机制
JVM JRE JDK 的区别
- JVM是一个虚拟的用于执行bytecode字节码的“虚拟计算机”
java写完之后,编译成字节码,再把字节码喂给JVM,JVM和操作系统打交道 - JRE包含java虚拟机、库函数、运行java应用程序所必须的文件
- JDK包含JRE,以及增加编译器和调试器等用于程序开发的文件
JDK包含JRE包含JVM
对象和类的关系
类是对象的模板,对象是类的抽象
栈 堆 方法区
栈里存放的是:存储堆中对象的引用,存储基本数据类型,方法调用时进栈、方法执行完退栈
堆里存放的是:创建的对象,数组
方法区在堆里(包含了常量池):存放静态变量,静态方法,字符串(在常量池里)
this的本质
this的本质为创建好的对象的地址
由于在构造方法调用前,对象已经创建。因此,在构造方法中也可以使用this代表“当前对象”
static关键字的说明
- static修饰的成员变量和方法,从属于类,普通变量和方法从属于对象。
- static修饰的成员方法,只能调用static修饰的成员方法和变量
- 非static修饰的成员方法,可以调用static修饰的成员方法和变量
静态初始化块
在类初始化的时候执行
在构造器之前执行
面向对象的三大特征
继承、封装、多态
继承要点
- 父类也叫超类、基类、派生类等
- 继承为单继承,接口可以多实现
- 子类继承父类,可以得到父类的全部属性和方法(除了父类的构造方法),但不见得可以直接访问(比如父类的私有属性和方法)
- 如果定义一个类时,没有调用extends,则它的父类是:java.lang.Ojbect
方法重写要点
- 方法名、形参列表相同
- 返回值类型和声明异常类型,子类小于等于父类
- 访问权限,子类大于父类
JDK提供的编译器、解释器
编译器:javac.exe
解释器:java.exe
super父类对象引用
- super是直接父类对象的引用。可以通过super来访问父类中被子类覆盖的方法或属性。
- 所有的子类,默认调用父类的构造方法。
- 无参构造方法默认加super();
- 有参构造方法的super()不会自己加上,如果想加,必须自己手动加上。
继承树追溯问题
封装作用:
- 提高代码的安全性
- 提高代码的复用性
- "高内聚":封装细节,便于修改内部代码,提高可维护性。
- "低耦合":简化外部调用,便于调用者使用,便于扩展和协作。
访问控制
修饰符 | 同一个类 | 同一个包 | 不同包的子类 | 所有类 |
---|---|---|---|---|
private | √ | |||
default | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
封装的使用细节
- 一般使用private访问权限。
- 提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,以提供对属性的赋值与读取操作
(boolean变量的get方法是is开头) - 一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法是public修饰。
JavaBean规则
- 无参构造函数
- getter/setter方法
- 属性私有化
多态
多态指同一个方法调用,由于对象不同可能会有不同的行为。
多态要点
- 多态是方法的多态
- 3个必要条件:继承,方法重写,父类引用指向子类对象
- 父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。
final关键字
作用:
- 修饰变量:被它修饰的变量不可改变
- 修饰方法:该方法不可被子类重写,但是可以重载
- 修饰类:修饰的类不能被继承
数组
声明:
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;
抽象类
使用要点:
- 有抽象方法的类只能定义成抽象类
- 抽象类不能实例化
- 抽象类可以包含属性、方法、构造方法,但是构造方法不能用来new实例,只能用来被子类调用。
- 抽象类只能用来被继承
- 抽象方法必须被子类实现
抽象类的意义: - 为子类提供统一的,规范的模板
- 子类必须实现相关的抽象方法
接口
- 只能是public默认
- 和类名采用相同的命名机制
- 接口可以多继承
- 接口中的属性只能是常量,总是:public static final修饰,不写也是
- 接口中的方法只能是:public abstract修饰。省略的话,也是。
内部类
- 成员内部类
- 包含了静态内部类和非静态内部类
- 可以使用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 {
}
}
- 匿名内部类
适合只需要使用一次的类
注意: - 匿名内部类没有访问修饰符
- 匿名内部类没有构造方法
- 局部内部类
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("年龄不能为负数");
}
本文来自博客园,作者:jsqup,转载请注明原文链接:https://www.cnblogs.com/jsqup/p/15945544.html