java学习笔记
第一阶段
chapter04 运算符
键盘输入
- Sacnner类表示 简单文本扫描器,在Java.util包
- 1、引入/导入Scanner类所在的包
- 2、创建Scanner对象,new创建一个对象
代码演示:
import java.util.Scanner;
public class test{
public static void main (String args[]){
Scanner myScanner = new Scanner(System.in);
System.out.println("输入名字:");
String name = myScanner.next();
System.out.println("姓名:" + name);
System.out.println("输入年龄:");
int age = myScanner.nextInt();
System.out.println("年龄:" + age);
char gender = myScanner.next().charAt(0); //从字符串中获取字符
}
}
String类型转换为double等类型
代码演示:
//string转double
public class BitOperator{
public static void main(String args[]){
String str = "123.4";
Double num1 = Double.parseDouble(str);
System.out.println(num1);
}
}
//char转string
public class BitOperator{
public static void main(String args[]){
char c = 'h';
Sring str = c + "";
System.out.println(str);
}
}
chapter05 程序控制
Switch-case语句
细节
-
Switch(表达式)中表达式的返回值必须是:byte,short,int ,char,enum,String
-
case子句中的值必须是常量(例如1,‘a’)或者常量表达式而不能是变量
-
break语句用来执行完最后一个case分支后使程序跳出Switch语句块
代码演示:
import java.util.Scanner;
public class Switchcase{
public static void main(String args[]){
Scanner myScanner = new Scanner(System.in);
int a = myScanner.nextInt();
switch(a){
case 1:
System.out.println("星期1");
break;
case 2:
System.out.println("星期2");
break;
default:
System.out.println("无匹配项");
}
}
}
跳转控制语句break-lable
- 当break语句出现在多层嵌套循环时,可以通过标签指明要终止的是哪一层语句块
- 实际应用中尽量避免使用标签(lable),易造成逻辑混乱
代码演示:
public class breaklable{
public static void main(String[] args){
lable1:
for(int i = 0 ;i < 10; i++){
lable2:
for(int j = 0 ; j < 10 ; j ++){
lable3:
for(int k = 0 ;k < 10 ;k ++){
if(i * j + k == 25){
System.out.println("i = " + i + " j = " + j + " k = " + k + "hhhh");
break lable2;
}
System.out.println("i = " + i + " j = " + j + " k = " + k);
}
}
}
}
}
chapter06 数组,排序,查找
数组array
- 可通过 array.length 来获得数组长度
- int[] array 等价于 int array[]
- 数组默认初始化为0
- Stirng array[] = {“abc” , “bcd” , “efg”} 静态初始化 字符串数组
- 开辟自定义长度数组有以下两种写法↓
//创建长度为5的数组
double array[] = new double[5];
//先声明,再分配空间
double array[];
array = new double[5]; //动态初始化
- 数组赋值实际上是地址赋值,例如:
int array1[] = {1,2,3};
int array2[] = array1;
array2[0] = 10;
//此时array1中的array[0]值也被修改为10
-
数组翻转
-
开辟一个新数组,将原数组翻转后,原数组指向第二个数组,则原数组会被回收
int array1[] = {1,2,3,4,5,6}; int len = array1.length; int array2[] = new int[len]; for(int i = 0 ;i < len ; i++){ array2[i] = array1[len - i - 1]; } array1 = array2;
-
字符串比较
- 顺序查找
import java.util.Scanner;
public class array01{
public static void main(String[] args){
Scanner myScanner = new Scanner(System.in);
String name[] = {"abc" , "efd" , "hij"};
String findname = myScanner.next();
for(int i = 0 ;i < name.length ; i++){
if(findname.equals(name[i])){ //使用equals来比较
System.out.println("该字符串存在");
}
}
}
}
二维数组
-
二维数组可以定义为int array[5] [ ]例如,每一行数据长度可不同
int array[][] = new int [5][]; for(int i = 0; i < 5 ; i++){ array[i] = new int[i]; } //这种写法也支持,每行元素个数可不一致 int arr[][] = new int[3][]; arr[0] = new int[4]; arr[1] = new int[3]; arr[2] = new int[5];
-
有int [] []array 和int [] array[]和 int arary[] []三种声明方法
随机数
使用方法
import java.util.Random;
Random random = new Random();
int a = random.nextInt(100); //0-100随机数
int randomnum = (int)Math.random()*100 + 1; //生成1-100之间的随机数
chapter07 类与对象
属性
示例:
class Cat{
String name;
String color;
int age;
}
Cat cat1 = new Cat();
cat1.name = "hhh";
cat1.color = "yellow";
cat1.age = 18;
方法
调用和定义示例:
public class Method01 {
public static void main(String[] args){
Person p1 = new Person();
p1.speak();
p1.cal01(1000);
}
}
class Person{
String name;
int age;
public void speak(){
System.out.println("喵喵喵");
}
public void cal01(int n){
int sum = 0;
for(int i = 1 ; i <= n ; i++){
sum += i;
}
System.out.println(sum);
}
}
类数组
例如:
Person[] person = new Person[3];
person[0] = new Person("jack" ,29 ,"teacher");
person[1] = new Person("marry" ,16 ,"student");
person[2] = new Person("harry" ,18 ,"boy");
参数传递机制
parameter n.参数
-
区分值传递和引用传递
class Person{ String name; int age; } class B{ public void test01(Person p){ p = null; //此时不会对原Person p造成影响,而是新开辟的test01栈中的p指向null } }
chapter08 递归
汉诺塔示例:
代码演示:
public class hanoiTower{
public static void main(String[] args){
Tower tower = new Tower();
tower.move(5 , 'A' , 'B' , 'C');
}
}
class Tower{
public void move(int num, char a,char b,char c){
if(num == 1){
System.out.println(a + "->" + c);
}else{
move(num - 1 ,a , c ,b);
System.out.println(a + "->" + c);
move(num - 1 , b ,c ,a);
}
}
}
八皇后问题:
代码演示:
public class EightQueen{
static char map[][] = new char[8][8];
static boolean col[] = new boolean[8];
static boolean row[] = new boolean[8];
static boolean dg[] = new boolean[20];
static boolean udg[] = new boolean[20];
static void find(int y){
if(y == 8){
for(int i = 0 ;i < 8;i++){
for(int j = 0 ;j < 8;j ++){
System.out.print(map[i][j]);
}
System.out.println();
}
System.out.println();
return ;
}else{
for(int i = 0 ;i < 8 ; i++){
if(!col[i] && !row[i] && !dg[y - i + 8] && !udg[i +y] ){
map[y][i] = 'Q';
col[i] = true;
row[i] = true;
udg[y + i] = true;
dg[y - i + 8] = true;
find(y + 1);
map[y][i] = '.';
col[i] = false;
row[i] = false;
udg[y + i] = false;
dg[y - i + 8] = false;
}
}
}
}
public static void main(String[] args){
for(int i = 0 ;i < 8; i++){
for(int j = 0; j< 8; j++){
map[i][j] = '.';
}
}
Queen queen = new Queen();
queen.find(0);
}
}
//参考acwing详解
细节要点:
- 清楚思路
- 只管当前一步做什么,不要试图想清楚递归后在做什么
chapter09方法重载
- 介绍
- java中允许同一个类中,多个同名方法的存在,但要求形参列表不一致,比如System.out.println();
- 重载的好处
- 1)减轻起名的麻烦
- 2)减轻记名的麻烦
重载示例:
public class OverLoad{
public static void main(String[] args){
myCalculator calculator = new myCalculator();
int res1 = calculator.Calculator(1,5);
double res2 = calculator.Calculator(2.45,3);
System.out.println(res1);
System.out.println(res2);
}
}
class myCalculator{
public int Calculator(int a,int b){
return a + b;
}
public double Calculator(double a,double b){
return a + b;
}
}
可变参数
对功能相同和方法名相同的方法可以使用如下方法
public class var{
public static void main(String[] args){
varparameter temp = new varparameter();
int res = 0;
res = temp.getsum(1,2,3,4,5,6);
System.out.println(res);
}
}
class varparameter{
public int getsum(int...nums){
int sum = 0;
for(int i = 0 ; i < nums.length ; i++){
sum += nums[i];
}
return sum;
}
}
注:上述代码中,类名var不可用Varparameter或者VarParameter代替,原因不详。
细节:
- 允许可变参数与基本类型参数放在同一个参数列表,但是可变参数必须放在最后
- 不允许多个可变参数在同一参数列表
作用域
1、主要的变量就是属性(成员变量)和局部变量
2、局部变量一般指成员方法中定义的变量,不可使用修饰符
3、全局变量(属性)可以不赋值使用,因为有初始值。而局部变量必须赋值后使用,无默认值。可以加修饰符,如static
构造器
public class constructor01{
public static void main(String[] args){
Person p1 = new Person(10 , "xiaoming");
Person p2 = new Person("abc");
System.out.println(p1.age + " " + p1.name);
System.out.println(p2.name);
}
}
class Person{
int age;
String name;
public Person(int pAge ,String pName){
age = pAge;
name = pName;
}
public Person(String pName){
name = pName;
}
}
- 用于属性的初始化
- 程序员没有定义构造器时,系统默认构造一个无参构造器如:Person() {};
注:
javap对class文件反编译
this关键字
简单说:调用那个对象this就是代表那个对象
this(参数列表) 用于调用本类的构造器
chapter10 包
基本语法
package com.ending
//package 关键字,表示打包
//com.ending 表示包名
import java.util.* //引入该包下的所有类
命名规则:
com.公司名.项目名.模块名
细节:
- 要导入不同包中的同名类时,只能导入一个,另一个必须写详细包名
访问修饰符
- public
- 公开级别,对外公开
- protected
- 受保护级别,只对子类及同一个包中的类公开
- 默认级别
- 无修饰符,向同一个包的类公开
- private
- 只有类本身可以访问,不对外公开
访问权限
本类 | 同包 | 子类 | 不同包 | |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
默认 | √ | √ | × | × |
peivate | √ | × | × | × |
封装
- 将set和get写在构造器中,可以保证安全并且验证数据
class Person{
public String name;
private int age;
private double salary;
public Person() {
}
public Person(String name, int age, double salary) {
this.setAge(age);
this.setName(name);
this.setSalary(salary);
}
public String getName() {
return name;
}
public void setName(String name) {
if(name.length() >= 2 && name.length() <= 6 ) {
this.name = name;
}else this.name = "默认用户";
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age >= 1 && age <= 120) {
this.age = age;
}else {
this.age = -1;
}
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
if(salary >= 0) {
this.salary = salary;
}else this.salary = -1;
}
}
继承
继承可以解决代码复用,当多个类中重复出现摸个属性时,可从中抽象出父类,子类 不需要重复定义,只需要extends继承。
基本语法
- 子类extends父类
- 子类自动拥有父类的属性和方法
- 父类又被叫做超类和基类
- 子类又叫派生类
细节
- 子类继承了父类的所有属性和方法,但是私有属性不能被子类访问,需要公共方法访问
- 子类必须调用父类的构造器,完成父类的初始化,默认使用super()调用父类的无参构造器
- 需要指定调用父类的哪一个构造器时,需要显式地调用:super(参数列表);super使用时需要放在构造器的第一行且super只能在构造器中使用
- this() 和super()不可共存,只能出现其中一个
- 所有类都是object的子类
- 父类构造器的调用不仅限于父类,将一直追溯到object类(顶级父类)
- 子类最多继承一个父类,如果过要求c继承b和a的属性,应该先让b继承c,a再继承b
- 不可滥用继承,必须满足is -a的关系
super
- super代表父类的应用,用于调用父类的属性和方法
基本语法
- 访问父类的属性,但不能访问父类的private属性
- 不能访问父类private方法
- 访问父类的构造器,只能放在构造器中,且只能写在构造器的第一条,只能出现一句,且不能和this同是出现
细节
- 使用super和this可以使方法和属性各司其职
- 当父类和子类中有相同属性和方法时,为了访问父类,就必须使用super
- super访问不仅限于直接父类,当多个父类拥有同名属性或方法时,super采用就近原则
重写/覆盖(override)
子类中的某个方法与父类中的方法名称,返回类型,参数一眼,那么我们就称子类的方法覆盖了父类的方法
- 子类不能缩小父类方法的权限
多态
方法或对象具有多种形态。基于封装和继承
对象的多态
- 一个对象的编译类型和运行类型可以不一致
- 编译类型在定义对象时就确定了,不可更改
- 运行类型是可以变化的
- 编译类型在 = 左边;运行类型在 = 右边;例如Animal animal = new Dog();此时 编译类型是Animal,运行类型是Dog
- 代码运行时,取决于运行类型
- 运行类型可根据需要来变更
- 访问属性看编译类型
- 访问方法,从运行类型开始向上查找
动态绑定机制
- 当调用方法时,该方法会和运行类型绑定
- 调用对象属性时,没有动态绑定机制,哪里声明,哪里使用
object类详解
== 与 equals对比
-
== 是比较运算符
- 可判断基本类型与引用类型
- 判断基本类型时,用于判断值是否相等
- 判断引用类型时,判断地址是否相等,即判断是否为同一对象
-
equals用于对比两串字符串是否相等
hashCode
- 提高具有哈希结构的容器的效率
- 如果引用的两个相同对象则哈希值一样
- 如果指向的是不同对象,则哈希值不一样
- 哈希值主要根据地址号来计算,但不等价于地址
ToString
用于返回全类名 + @ +哈希值得16进制数
//Object中ToString的源码
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
一般toString用于返回对象的所有属性
重写toString方法
class Monster{
private String name;
private int sal;
public Monster(String name, int sal) {
this.name = name;
this.sal = sal;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSal() {
return sal;
}
public void setSal(int sal) {
this.sal = sal;
}
@Override
public String toString() {
return "Monster{" +
"name='" + name + '\'' +
", sal=" + sal +
'}';
}
}
System.out.println(monster);
// 这个语句默认是调用ToString
//与下面语句等价
System.out.println(monster.toString());
Date类
使用方法
Date date = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); //格式转换
System.out.println(sdf.format(date)); //转换格式之后输出
第二阶段
类变量
也叫静态变量/静态属性,是该类所有对象公用的变量.
-
定义语法
- 修饰符 + static + 数据类型 + 变量名 或者 static+ 修饰符 + 数据类型 + 变量名 两种写法
-
访问形式
- 类名.变量名 或者 对象名.变量名 (一般使用类名.变量名的方法)
类方法
也加静态方法
语法规则: 修饰符 + static + 返回数据类型 + 方法名 +(参数列表) { };
代码块
用于当多个构造器中代码冗余时,使代码简洁高效。是构造器的一种补充机制,提高代码的复用性
class test{
private String name;
private double age;
{
System.out.println("代码块被调用");
}
public test(String name) {
this.name = name;
}
public test(String name, double age) {
this.name = name;
this.age = age;
}
}
上述实例中,两个构造器均调用代码块内容
代码块细节
-
static代码块也叫做静态代码块,作用是对类的初始化,而且随着类的加载而执行,并且只会执行一次。如果是普通代码块,每创建一次对象,就执行。
-
类什么时候被加载
- 创建对象实例时(new)
- 创建子对象实例时,父类会被加载
- 使用类的静态成员时
public class test001 {
public static void main(String[] args) {
test test1 = new test();
test test2 = new test();
}
}
class test{
static {
System.out.println("代码块被执行");
}
}
//此时test中的代码块只被执行一次,因为static代码块只有类被加载时才执行.且只执行一次
//区别于普通代码块,普通代码块每创建一个对象实例,就会执行一次
- 普通代码块,在加载时会被隐式调用,创建一次,调用一次.如果只是使用类的静态成员,普通代码块不会被执行.(可以将普通代码块看作是构造器的补充,因此只在new一个对象时才会被调用)
单例设计模式
什么是单例模式?
单例(单个实例)
1、所谓的单例设计模式,就是采取一定的方法保证在整个软件的系统中,对某个类只能创建一个对象实例,并且该类只提供一个获取该实例的方法
2、单例模式有两种方式:1)饿汉式和2)懒汉式
饿汉式
步骤如下:
- 构造器私有化(防止直接new)
- 类的内部创建对象
- 向外暴露一个静态的公共方法getInstance()
- 代码实现
package com.ending.singleTon;
public class SingleTon01 {
public static void main(String[] args) {
Girlfriend instance = Girlfriend.getInstance();
System.out.println(instance);
}
}
class Girlfriend{
private String name;
private static Girlfriend gf = new Girlfriend("hhh");
private Girlfriend(String name){
this.name = name;
}
static Girlfriend getInstance(){
return gf;
}
}
懒汉式
只在调用是创建对象,第二次调用时已经创建所以返回第一次创建的对象,不会造成资源的浪费
package com.ending.singleTon;
public class SingleTon02 {
public static void main(String[] args) {
Cat instance = Cat.getInstance();
System.out.println(instance);
}
}
class Cat{
private String name;
public static int n = 100;
private static Cat cat; //此时cat为null
private Cat(String name) {
this.name = name;
}
static Cat getInstance(){
if(cat == null){
Cat cat = new Cat("hhhh");
}
return cat;
}
}
二者对比
- 两者最大的区别在于创建对象的时机不同,饿汉在加载对象时就创建,懒汉在使用时才加载
- 懒汉式存在线程安全问题
- 饿汉式存在资源浪费的可能。如果一个对象创建了而没有被使用,那么资源被浪费。
- 在javaSE标准类中,java.lang.Runtime就是典型的单例模式
final
final可以用于修饰类,属性,方法,局部变量
final修饰的属性一般被叫做常量,用XXX_XXX_XXX命名
使用场景
- 当一个类不允许被继承时,用final修饰该类
- 当不允许父类的某个方法被子类重写时
- 当不允许某个属性被修改时
- 当不允许局部变量被修改时
final class A {
public final int n = 100;
}//此时A不允许被继承
class B{
public final void Bmethod(){
System.out.println("B方法被使用");
}
}//此时Bmethod不允许被子类重写覆盖
class C{
public final int n = 100;
public void Cmethod(){
final int x = 1000;
}
}//此时n不允许被修改,且x不允许被修改
final细节
-
final修饰的属性,必须赋初值,并且不允许被修改
- 非静态属性,可以在定义时、构造器、代码块中赋值
- 静态属性,只能在定义时,和静态代码块中赋初值
-
final类不可被继承,但是可以实例化
-
一般来说,一个类如果已经是final类对了,就没有必要再将方法修饰成final方法因为此时该类已经不能被继承,所以也就不允许被重写
-
final不能修饰构造器
-
final往往与static搭配使用,效率更高,不会导致类被加载,底层编译器做了优化处理
-
包装类(Integer、Double、Float、Boolean、String等)是final类
抽象类
抽象类介绍
- 用abstract关键字来修饰一个类时,这个类就叫抽象类
- 用abstract关键字修饰一个方法时,这个方法就是抽象方法,该方法没有方法体
- 抽象类的价值更多是在于设计,是设计者设计好后,让子类继承并实现抽象类
- 考官爱考,在框架和设计模式使用比较多
abstract class Animal{
public abstract void eat();
}
细节
- 抽象类不能被实例化
- 抽象类不一定要包含abstract方法
- 一旦类中包含abstract方法,该类只能为抽象类
- abstract只能修饰类和方法,不能用来修饰属性和其他
- 抽象类的本质还是类,可以有任意成员,比如构造器,非抽象方法,静态属性等
- 抽象方法不能有方法主体
- 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它也定义为抽象类
- 抽象方法不能使用private,final,static来修饰因为这些修饰符本身会影响子类对该方法的重写
抽象类应用
模板设计模式
接口
基本介绍:接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来
public class Interface001 {
public static void main(String[] args) {
BBB bbb = new BBB();
bbb.hi();
}
}
interface InterfaceAAA{
public void hi();
}
class BBB implements InterfaceAAA{
public void hi(){
System.out.println("hi!!!");
}
}
接口细节
-
接口不能被实例化
-
接口中所有方法都是public,接口中抽象方法,可以不用abstract修饰例如:void aaa() {}实际上是abstract void aaa();
-
IDEA中写接口中的全部方法可以使用Alt+Enter来自动补全
-
abstract类可以不实现接口中的方法
-
一个类可以实现多个接口,并且要实现所有接口中的方法
-
接口可以继承其他接口,但是接口不能继承其他类
-
接口中的属性都是 final public static属性的
-
接口访问形式 接口名XXX.属性
-
接口的修饰符,和类一样,只能是public和默认
-
当一个类实现某个接口时,允许该类直接访问接口中的属性
接口多态性
- 多态参数
public class Interface001 {
public static void main(String[] args) {
a a1 = new a();
b b1 = new b();
c c1 = new c();
c1.test(a1);
c1.test(b1); //此时体现多态
}
}
interface InterfaceAAA{
public void hi();
}
class a implements InterfaceAAA{
@Override
public void hi() {
System.out.println("AAA'hi");
}
}
class b implements InterfaceAAA{
@Override
public void hi(){
System.out.println("hi");
}
}
class c{
public void test(InterfaceAAA A){
A.hi();
}
}
如上例,c.test(),可以接收a,b两个对象,即可接收实现了同一接口的对象
- 多态数组
接口虽不能被实例化,但是可以创建数组。
InterfaceAAA[] interfaceAAAS = new InterfaceAAA[3];
- 接口存在多态传递现象
内部类
在一个外部类中嵌套一个类,叫做内部类,内部类的最大优点是可以直接访问私有属性,并且可以体现类与类之间的包含关系。
局部内部类
说明:局部内部类时定义在外部类的局部位置,比如方法中,并且有类名。
- 内部类可以直接访问外部类的所有成员,包括私有属性
- 不能添加修饰符,因为他的地位就是一个局部变量,局部变量是不能使用修饰符的,但是可以添加final,因为局部变量也可以添加final
- 作用域:仅仅在定义他的方法或者代码块中。
- 局部内部类访问外部成员,直接访问即可
- 外部类访问局部内部类的成员,访问方式:先创建对象,再访问(注意:必须是在作用域内)
- 如果外部类成员名和内部类成员名重复时,默认采用就近原则,如果想访问外部类的成员,需采用(外部类名.this.成员名的方式)
记住:局部内部类定义在方法/或者代码块中,作用域在方法体或者代码块中,其本质任然是一个类
public class InterClass01 {
public static void main(String[] args) {
outer outer001 = new outer(200);
outer001.f1();
}
}
class outer{
private int n = 100;
public outer(int n) {
this.n = n;
}
{
System.out.println("m1()");
}
public void f1(){
class inner{
int n2 = 20;
public void f2() {
System.out.println(n);
}
}
inner inner001 = new inner();
inner001.f2();
}
}
匿名内部类
public class InnerClassExercise {
public static void main(String[] args) {
f1(new IA() {
@Override
public void show() {
System.out.println("这是匿名内部类的使用演示");
}
});
}
public static void f1(IA ia) {
ia.show();
}
}
interface IA{
void show();
}
成员内部类
- 定义在成员位置的内部类,而不是在方法体中的(与匿名 内部类区分)
- 可以访问外部类的所有属性,包括私有属性
- 内部类作用范围:和外部类的其他成员一样,为整个类体,在外部类的成员方法构建一个内部类实体,再调佣方法
- 其他外部类访问内部成员类:把内部类当做外部类的一个属性,如Outer.Inner inner = Outer.new Inner();或者在外部类中专门写一个方法用于返回内部类,如下演示
public class InnerClassTest01 {
public static void main(String[] args) {
outer01 outer = new outer01();
outer.f2();
}
}
class outer01{
private int n1 = 1000;
public void f1(){
System.out.println("hi");
}
class inner01{
public void f2(){
System.out.println("访问外部类测试outer = " + n1);
}
}
public void f2(){
inner01 inner = new inner01();
inner.f2();
}
//返回内部类
public inner01 getinner(){
return new innner01();
}
}
静态内部类
-
定义为static的内部类成员
-
定义在成员位置的类,本质还是一个成员,所以可以加private,public等修饰符
-
只能访问外部类中的静态属性,而不能访问非静态属性
-
其他外部类也可以用类名访问静态内部类,但是必须满足访问权限的限制,在静态内部类中加private修饰,不可被其他外部类访问
public class InnerClassTest01 {
public static void main(String[] args) {
outer01 outer = new outer01();
outer.f2();
}
}
class outer01{
private static int n1 = 1000;
static class inner01{
public void f2(){
System.out.println("访问外部类静态属性测试outer = " + n1);
}
}
public void f2(){
inner01 inner = new inner01();
inner.f2();
}
}
枚举和注解
自定义实现枚举
public class Enumeration01 {
public static void main(String[] args) {
System.out.println(Season.AUTUMN);
System.out.println(Season.SPRING);
System.out.println(Season.SUMMER);
System.out.println(Season.WINTER);
}
}
class Season{
private String name;
private String describe;
public static final Season SPRING = new Season("spring","温暖");
public static final Season SUMMER = new Season("summer","炎热");
public static final Season AUTUMN = new Season("autumn","凉爽");
public static final Season WINTER = new Season("winter","寒冷");
private Season(String name, String describe) {
this.name = name;
this.describe = describe;
}
public String getName() {
return name;
}
public String getDescribe() {
return describe;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", describe='" + describe + '\'' +
'}';
}
}
enum关键字实现枚举
- 定义常量对象必须写在最前面
- 使用enum类开发时,默认会继承enum类,并且是final类
- 使用无参构造器时,括号和参数列表均可省略
public class Enumeration02 {
public static void main(String[] args) {
System.out.println(Season02.SPRING);
System.out.println(Season02.SUMMER);
}
}
enum Season02{
SPRING("春天","温暖"),SUMMER("夏天","炎热");
//调用构造器
private String name;
private String desc;
Season02(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
}
- 本质就是ToString
public class Enumeration03 {
public static void main(String[] args) {
System.out.println(Gender.BOY);
}
}
enum Gender{
BOY,GIRL;
//相当于调用无参构造器
}
enum成员方法
-
name(); 输出枚举对象的名称
-
ordinal() 输出该枚举对象的编号
-
values() 方法返回一个枚举变量的数组详见下方代码
-
valueof() 方法将一段字符串与枚举对象进行比对,并返回枚举对象,比对失败则报错。
-
compareTo() 将两个枚举对象的编号进行对比,并且返回编号差值
public class Enumeration02 {
public static void main(String[] args) {
Season02 spring = Season02.SPRING;
System.out.println(spring.name());
System.out.println(spring.ordinal());
Season02 values[] = Season02.values();
for(Season02 season : values){
System.out.println(season);
}
Season02 summer = Season02.valueOf("SUMMER");
System.out.println(summer);
System.out.println(Season02.SPRING.compareTo(Season02.SUMMER));
}
}
enum Season02{
SPRING("春天","温暖"),SUMMER("夏天","炎热");
private String name;
private String desc;
Season02(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
}
enum细节
- enum类不可继承其他类:在底层源码中,enum类已经继承了类(隐式继承),如下反编译源码
- enum类本质还是一个类,可以实现接口
注解
override
- 在程序中标明@override,编译器会检查该方法是否重写
- 只能用于方法标注
deprecated
- 用于表示某个程序元素已过时
- 可以修饰方法,类,字段,包,参数等等
- @deprecated的作用可以做到新旧版本的兼容和过渡
supresswarring
- 用于抑制警告warring
元注解
章末作业
public class Homework001 {
public static void main(String[] args) {
Cellphone cellphone = new Cellphone();
cellphone.workTest(new Caculate() {
@Override
public double work(double n1, double n2) {
return n1*n2;
}
},10, 8);
}
}
interface Caculate{
public double work(double n1, double n2);
}
class Cellphone{
public void workTest(Caculate caculate,double n1,double n2){
double result = caculate.work(n1,n2);
System.out.println("result = " + result);
}
}
异常处理
运行时异常
- NullPointerException 空指针异常
- ArithmeticException 数学运算异常
- ArrayIndexOutOfBoundsException 数组越界异常
- ClassCastException 类型转换异常
- NumberFormatExceptio 数字格式不正确异常
throws细节
- 编译异常必须处理,try-catch或者throws
- 对于运行异常,程序中如果没有异常处理,默认是throws,最终将异常抛给JVM
- 子类重写父类的方法,子类抛出的异常要么与父类一致,要么是父类异常的子类型
- 在throws中,如果有try-catch,就相当于有异常处理,可以不必有throws
- 一旦在try代码块中抛出异常,则在try块中抛出异常的语句后面的语句将不再被执行
自定义异常处理
public class CustomException {
public static void main(String[] args) {
int age = 20;
if(!(age >= 18 && age <= 120)){
throw new AgeException("年龄异常");
}
System.out.println("运行中");
}
}
class AgeException extends RuntimeException{
public AgeException(String message) {
super(message);
}
}
课后习题
public class HomeWork001 {
public static void main(String[] args) {
int length = args.length;
try {
if(length != 2){
throw new ArrayIndexOutOfBoundsException("参数个数不正确");
}
int n1 = Integer.parseInt(args[0]);
int n2 = Integer.parseInt(args[1]);
double res = cal(n1,n2);
System.out.println("res = " + res);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println(e.getMessage());;
} catch(NumberFormatException e){
System.out.println("参数格式不正确");
}catch(ArithmeticException e){
System.out.println("参数除0异常");
}
System.out.println("程序运行结束");
}
public static double cal(int n1,int n2){
return (double)n1/n2;
}
}
常用类
String
集合
迭代器
List list = new ArrayList();
list.add(10);
list.add("huhu");
list.add(45687);
Iterator iterator = list.iterator();
while (iterator.hasNext()) { //IDEA创建while循环快捷键itit
Object next = iterator.next();
System.out.println(next);
}
增强for循环
int nums[] = {1,2,3,4,5,6}; //底层还是迭代器
for(int i : nums){
System.out.println(i);
}
List接口
set接口
也为collection的子接口,方法与collection一致
- 无序
- 不允许重复
- 可以添加一个null
- 取出的数据不是输入顺序,但是每次输出都是一个固定的顺序
遍历形式
可以使用迭代器和增强for循环及其他普通方法
HashSet
是set接口的实现类
- 实现了Set接口
- 实际上是HashMap
- 不保证存放数据顺序和取出顺序一致,取决于hash后的索引
HashSet底层机制说明
- 底层是HashMap
- 添加一个元素时,先得到hash值,再转换成索引值。
- 找到存储数据表table,看这个索引位置是否已经存放有元素
- 如果有,调用equals方法进行比较,如果相同,放弃添加。如果不同,则添加到最后。
- 在java8中,如果一条链表的元素个数到达TREEILY_THRESHOLD(默认是8)并且table的大小>= MIN_TREEIFY_CAPACITY(默认是64),就会进行树化(红黑树)。
Map接口(JDK8)
-
存放键值对(映射)数据(key-value)
-
key和value可以任意值,被封装到HashMap$Node对象中
-
Map中的key不允许重复,原因是存储下标通过key计算得到(重复时,前一个会被替换)
-
Map中的value可以重复
-
key和value都可以为null,但是key为null只能有一个,value不限
-
key和value存在一一对应的关系,可以通过key来找到value