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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?