导图社区 Java_yangmufa
这是一篇关于Java的思维导图,主要内容有基础语法、面向对象、学习方法、—阶段面试题、API文档。
编辑于2022-06-18 16:05:49Center
基础语法
语法
学习JAVA须知概念
JDK
java development kit java开发包,主要用于做java开发
JRE
Java Runtime Environment java运行时环境,主要用于执行测试 java代码
JVM
Java Vritual Machine java虚拟机,用来解释执行字节码文件【创建.java结尾的文件,通过编译为.class的文件,jvm负责处理字节码文件,转换成1和0】
Java注释分三种
1.单行注释 : // 解释性的内容
2.多行注释: /* 解释性的内容 */
3.文档注释:/** 文档注释内容 */
数据类型
八大基本数据类型
整型
byte
1byte = 8 bit
取值范围是-128~127【-2的7次方到2的7次方-1】
short
2byte = 16 bit
取值范围是-32768~32767【-2的15次方到2的15次方-1】
int
整数的直接量默认是int类型
4byte = 32 bit
取值范围是-2147483648~2147483647【-2的31次方到2的31次方-1】
long
8byte = 64 bit
取值范围是-9223372036854774808~9223372036854774807【-2的63次方到2的63次方-1】
浮点型
内存存储结构和整型不同,比long的范围还大
float
4byte = 32 bit
取值范围是3.402823e+38 ~ 1.401298e-45
double
小数直接量是double类型 -900万万亿 ~ 900万万亿
8byte = 64 bit
取值范围是1.797693e+308~ 4.9000000e-324
字符型
必须用单引号,否则报错
char
2byte = 16 bit
取值范围是0~65535【2的16次方-1】
布尔型
boolean
1byte = 8 bit
取值范围false、true
引用数据类型
自定义的类 也是一种数据类型 是引用类型,null是引用类型的初始值
字符串String
String内存图解
字符串不可变性图示
字符串常量池图示
字符串面试题图示
String类型定义方式
静态方式
String s = "ABC";
可以进行复用
动态释放
String s = new String("ABC")
不可复用
String常用API
正则表达式、匹配
常见语法 1.普通字符 字母、数字、汉字、下划线、以及没有特殊定义的标点符号,都是"普通字符"。 表达式中的普通字符,在匹配一个字符串的时候,匹配与之相同的一个字符串。 例如: bcd 正则, 在匹配字符串"bcd"时, 结果是: 可以匹配, 匹配到的内容就是: "bcd" bcd 正则, 在匹配字符串"abcde"时, 结果是: 不匹配 .*bcd.* 正则, 在匹配字符串"abcde"时, 结果是: 可以匹配, 匹配到的内容就是: "bcd" 其中点(.)表示任意一个字符, (.*)表示此处可以出现0或多个任意字符 .*bcd.* 正则, 在匹配字符串"abc de"时, 结果是: 不匹配 2.自定义能够匹配 '多种字符' 的表达式 使用方括号 [ ] 包含一系列字符,能够匹配其中任意一个字符。 用 [^ ] 包含一系列字符,则能够匹配其中字符之外的任意一个字符。 同样的道理,虽然可以匹配其中任意一个,但是只能是一个,不是多个。 例如: [abc], 能匹配 "a" 或 "b" 或 "c" 中的任何一个字符串, 且只能匹配一个 比如"a"、"b"、"c" 等这些字符串都可以被 [abc] 匹配。 比如"d"、"e"、"f" 等这些字符串都不可以被 [abc] 匹配。 [^abc], 能匹配 "a","b","c" 之外的任何一个字符串, 且只能匹配一个 [a-z], 匹配26个小写字母, [a-zA-Z0-9], 匹配 26个小写字母、26个大写字母, 以及 数字0-9 中的任何一个 [^a-zA-Z], 排除英文字母 [^0-9], 排除数字0-9 [a-z][0-9], 匹配一个字母(a-z之间的)和一个数字(0-9之间的) 3.预定义字符类 . 表示任意一个字符,如果就想匹配 '.' 字符本身,可以使用: \. 这里的反斜杠表示转义 \d 匹配数字, 相当于[0-9] \D 排除数字, 相当于[^0-9] \w 匹配字母+数字, 相当于[a-zA-Z0-9] \W 排除字母以及数字, 相当于[^a-zA-Z0-9] 4.匹配字符出现的次数 [abc]?, ?号表示前面的字符出现0次, 或者1次(最多1次) [abc]+, +号表示前面的字符出现>=1次(至少1次) [abc]*, *号表示前面的字符出现>=0次(任意次) [abc]{n}, {n}表示前面的字符恰好出现 n 次 [abc]{n,}, {n,}表示前面的字符出现 >=n 次 [abc]{n,m}, {n,m}表示前面的字符出现 >=n 次, 但 <=m 次 5. [a-z&&[^bc]] 表示的是 26个小写字母中,除了bc 不可以写,其它都可以写 6. 分组 (abc){3} 表示:可以视为abc为一组 至少出现3组的意思 (abc|def){3} 表示:可以视为abc 或 def 为一组 至少出现3组的意思
indexOf
如果返回为-1,则意味着字符串不存在
charAt
lastIndexOf
扩展
StringBuffer
StringBuilder
1、首次创建对象的时候开辟了16个长度的数组空间,如果超过16,下一次就增加到32长度 2、和String字符串拼接相比,执行效率高
数组
string[] s=new string[3]; //赋值 s[0]="a"; s[1]="b"; s[2]="c"; //修改 s[1]="b1"; 需要知道数组的长度,往数组里面添加元素只能通过index的方式
数组拷贝
Arrays.copyOf
案例
class test{ public static void main(String[] args) { int i = 0; int[] a = {}; while (i<5) { a = Arrays.copyOf(a,a.length+1); i++ ; a[a.length-1] = i; } System.out.println(Arrays.toString(a)); } }
System.arraycopy
更多是用在两个数组之间的copy
案例
class test1 { public static void main(String[] args) { int[] arr1 = {50, 80, 60, 40, 10}; int[] arr2 = {1, 1, 1, 1, 1}; System.arraycopy(arr1, 1, arr2, 2, (arr1.length-2)); System.out.println(Arrays.toString(arr2)); } }
自定义类也属于引用数据类型
toString
重写toString是为了能获取对象中的所有的属性,方便简约
equals()
默认equals方法比较的是两个对象的内容和地址是否相同 String类就是重写了equals,比较的是内容是否相同
变量及命名规范
1.整数直接量,可以直接赋值给 byte 、short 、char 但是不能超过当前类型可存储的范围。 2.byte、shor、char 类型如果在进行运算时,系统自动将其结果转换为int类型。
变量命名规则和规范
变量名只能以英文字母、下划线、$开头
变量名严格区分大小写
userName和UserName不是同一个变量
变量名需要见名知意【英文】
遵循小驼峰的命名方式
例如userName、birthDay
类的命名遵循大驼峰命名【帕斯卡命名法】
变量类型转换
自动类型转换(隐式转换)
public class learn05 { public static void main(String[] args) { short a = 126; int b = a; //类型自动转换的前提是小范围往大范围 } }
小范围的变量赋值给大范围的变量,发生自动类型转换
强制类型转换(显式转换)
public class Demo04 { public static void main(String[] args) { short a = 126; byte b = (byte) (a+2); //大范围的往小范围,发生强制类型转换,会出现精度缺失的问题 System.out.println(b); } }
溢出/精度缺失等风险
溢出不是错误,但是需要避免,没有参考价值
浮点型
案例1
public static void main(String[] args) { double p = Math.PI; float x = (float) p; System.out.println(p); System.out.println(x); }
整形
案例1
public class Demo03 { public static void main(String[] args) { int max = Integer.MAX_VALUE; int min = Integer.MIN_VALUE; long current_int = max + 1L; System.out.println("max: " + max); System.out.println("max+1: " + max+1); System.out.println("max+2: " + max+2); System.out.println("这是一个long类型的10进制输出的值: " + current_int); if (min == max+1){ System.out.println("success"); } } }
案例2
public class Demo04 { public static void main(String[] args) { byte a = Byte.MAX_VALUE; System.out.println(a); int c = (int)a -1; System.out.println(c); System.out.println((byte)(a+1)); } }
大范围的变量赋值给小范围的变量,需要进行强制类型转换
常用关键字
访问修饰符的引入
1、可以修饰属性、方法、类(一般不用) 2、用来隐藏一些内容,用来暴露一些内容 3、属性封装:数据私有化,方法公开化
public
公开的, 访问权限最大,其它位置都可以。
protected
保护的,访问权限在本类,同包子类,同包类,不同包的子类 ,不同的类不可以! interface在jdk1.8之后可以实现普通方法,用default修饰
friendly
什么都不写,访问权限是本类和同包类都可以访问。
private
私有的,访问权限最小,只能当前类内部可见 封装特性,引入get set方法
总结
 public class Aoo { private int a ;//私有的属性 public int b;//公开的属性 int c; //默认级别的属性 protected static int d;//保护级别的属性 // protected int d;//保护级别的属性 void fun3(){ //默认级别的方法 } public void fun2(){ //公开的方法 c = 10;//本类可用 fun3();//本类可用 } private void fun(){ //私有方法 a = 10;//本类都可以用a } } class HaHa extends Aoo { public static void main(String[] args) { HaHa haHa = new HaHa(); System.out.println(HaHa.d); } }
void
定义一个方法,如果没有返回值,用void代替
this
this可以代表任何对象,当this出现在方法中时,它代表的对象是不确定的,但它的类型是确定的,它所代表的对象只能是当前类;只有当这个方法被调用时,它所代表的对象才确定下来;谁调用这个方法,this就代表谁。
this(),可以调用本类中的其他构造方法
本构造方法内使用,访问其他构造方法
案例
public class Constractor { int year; int month; int day; //无参数构造方法 public Constractor() { this(2019,1,1); } //有参数构造方法 Constractor(int year, int month, int day) { this.year = year; this.month = month; this.day = day; } }
super
super.变量,表示访问父类中的成员属性
super()调用父类中的无参构造方法
每一个类的构造方法第一句都是super();如果这个类不继承任何一个类,那么就具有Object类的特性,是所有类的祖先
extends
表示继承的意思,就是子类继承父类的关键字
子类也叫派生类
父类也叫超类或者基类
将子类中共性的属性或方法提取到父类叫泛化
变量名不能使用关键字
50个关键字
 abstract 表明类或者成员方法具有抽象属性 assert 断言,用来进行程序调试 boolean 基本数据类型之一,声明布尔类型的关键字 break 提前跳出一个块 byte 基本数据类型之一,字节类型 case 用在switch语句之中,表示其中的一个分支 catch 用在异常处理中,用来捕捉异常 char 基本数据类型之一,字符类型 class 声明一个类, const 保留关键字,没有具体含义 continue 回到一个块的开始处 default 默认,例如,用在switch语句中,表明一个默认的分支。Java8 中也作用于声明接口函数的默认实现 do 用在do-while循环结构中 double 基本数据类型之一,双精度浮点数类型 else 用在条件语句中,表明当条件不成立时的分支 enum 枚举 extends 表明一个类型是另一个类型的子类型。对于类,可以是另一个类或者抽象类;对于接口,可以是另一个接口 final 用来说明最终属性,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成员域的值不能被改变,用来定义常量 finally 用于处理异常情况,用来声明一个基本肯定会被执行到的语句块 float 基本数据类型之一,单精度浮点数类型 for 一种循环结构的引导词 goto 保留关键字,没有具体含义 if 条件语句的引导词 implements 表明一个类实现了给定的接口 import 表明要访问指定的类或包 instanceof 用来测试一个对象是否是指定类型的实例对象 int 基本数据类型之一,整数类型 interface 接口 long 基本数据类型之一,长整数类型 native 用来声明一个方法是由与计算机相关的语言(如C/C++/FORTRAN语言)实现的 new 用来创建新实例对象 package 包 private 一种访问控制方式:私用模式 protected 一种访问控制方式:保护模式 public 一种访问控制方式:共用模式 return 从成员方法中返回数据 short 基本数据类型之一,短整数类型 static 表明具有静态属性 strictfp 用来声明FP_strict(单精度或双精度浮点数)表达式遵循IEEE 754算术规范 super 表明当前对象的父类型的引用或者父类型的构造方法 switch 分支语句结构的引导词 synchronized 表明一段代码需要同步执行 this 指向当前实例对象的引用 throw 抛出一个异常 throws 声明在当前定义的成员方法中所有需要抛出的异常 transient 声明不用序列化的成员域 try 尝试一个可能抛出异常的程序块 void 声明当前成员方法没有返回值 volatile 表明两个或者多个变量必须同步地发生变化 while 用在循环结构中
abstract
1、用来修饰抽象类,抽象类是不可以new对象的 2、含有抽象方法的类一定是抽象类,但是抽象类可以没有抽象方法 3、抽象方法可以有构造方法 4、如果普通类继承抽象类,那就需要重写抽象类中所有的抽象方法
interface
接口
implements
和interface是对应关系, 实现接口的抽象方法就用implements关键字
final
修饰变量
final修饰变量时 要写在变量类型前方
成员变量被final修饰,声明变量的时候必须做初始化操作
局部变量声明用final声明的变量,可以在之后初始化,但是不能二次赋值
修饰方法
final修饰方法时 要写在方法返回值前方
用fianl修饰的方法,该方法是不允许被子类重写的!
修饰类
final修饰类时 要写在class 前面
证明这个类不能被继承,断子绝孙
static
静态变量和实例变量的区别
静态变量是存放在方法区的,在class字节码文件加载之后就生效了,只会加载一次 实例变量是创建对象后,才能访问的,且每个对象的变量都是独立的,相互不影响
static final
修饰成员变量为常量
运算符
运算符分类
数学运算符
+、-、*、/、%、++、--
案例1
int a = 5; int b = 4; int c = --a; int d = b--; System.out.println(a); System.out.println(b); System.out.println(c); System.out.println(d); 4344 ++或者--在前,先做计算,然后做赋值 ++后者--在后,先做赋值,后做计算
自增自减运算符
++、--
关系运算符
>、<、==、<=、>=、!=
位运算符
案例1
System.out.println(100&200); //转换成二进制,进行运算后,打印出来的是十进制数 A = 0011 1100 B = 0000 1101 ----------------- A&B = 0000 1100 A | B = 0011 1101 A ^ B = 0011 0001 ~A= 1100 0011 & 如果相对应位都是1,则结果为1,否则为0 (A&B),得到12,即0000 1100 | 如果相对应位都是 0,则结果为 0,否则为 1 (A | B)得到61,即 0011 1101 ^ 如果相对应位值相同,则结果为0,否则为1 (A ^ B)得到49,即 0011 0001 〜 按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 (〜A)得到-61,即1100 0011 << 按位左移运算符。左操作数按位左移右操作数指定的位数。 A << 2得到240,即 1111 0000 >> 按位右移运算符。左操作数按位右移右操作数指定的位数。 A >> 2得到15即 1111 >>> 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 public class Test { public static void main(String[] args) { int a = 60; /* 60 = 0011 1100 */ int b = 13; /* 13 = 0000 1101 */ int c = 0; c = a & b; /* 12 = 0000 1100 */ System.out.println("a & b = " + c ); c = a | b; /* 61 = 0011 1101 */ System.out.println("a | b = " + c ); c = a ^ b; /* 49 = 0011 0001 */ System.out.println("a ^ b = " + c ); c = ~a; /*-61 = 1100 0011 */ System.out.println("~a = " + c ); c = a << 2; /* 240 = 1111 0000 */ System.out.println("a << 2 = " + c ); c = a >> 2; /* 15 = 1111 */ System.out.println("a >> 2 = " + c ); c = a >>> 2; /* 15 = 0000 1111 */ System.out.println("a >>> 2 = " + c ); } } A>>>2得到15即0000 1111
逻辑运算符
&
&&
|
||
&&和&都是表示并且,区别是&&只要第一个条件返回true,后面条件就不再判断执行,直接返回,执行短路操作;同样的 | 和 || 也是一样,两个 | 表示遇到满足的条件就返回,单个 | 也是全部执行一次判断再返回【但是做逻辑运算时候|和&基本不用】
!
^
赋值运算符
1、赋值号: = 赋值的顺序,将赋值号右边的内容 给左边变量的过程. 2、扩展赋值: += -= /= *= %= 在变量的自身基础上,进行运算然后将结果再赋值给自身。
变量类型 名称 = 值/表达式 ;
复合型赋值(扩展运算符) +=、-=、*=、/=、%=
案例1
public class SwitchCaseDemo { public static void main(String[] args) { byte a = 7; a = (byte) (a * 7); System.out.println(a); //扩展运算符自动帮你强制类型转换了 a *= 7; //这个效果等价于 a = (byte) (a * 7) System.out.println(a); } }
字符串拼接运算符
字符是char类型 要用单引号来存储1个字符! 字符串是String类型,要用双引号来存储,存储一串字符! 1.使用+号时,如果两边的内容都是数值的话,则会进行运算操作! 2.使用+号时,如果有一方是字符串类型,则会进行链接(拼接)操作,则整体会变成一个字符串。
案例
String name = "乐磊"; int age = 18; System.out.println("大家好,我叫"+name+",我的年龄是"+age); System.out.println(10+10+""+30);//"2030" System.out.println(""+10+10+30);//"101030" System.out.println(10+10+30+"");//"50"
运算符的优先级
案例
public class Demo05 { public static void main(String[] args) { int a = 13; int b = (a + 13) * 12; System.out.println(b); } } 赋值运算优先级最低
运算类型
单元运算
只有一个变量参与运算
二元运算
有两个变量参与运算
三元运算
有三个变量参与运算
boolean-exp?value0:value1
案例
int number1 = 10; int number2 = 20; // 判断的逻辑 ? 成立返回值1 : 不成立 返回值2 int max = number1 > number2 ? number1: number2; System.out.println(max); //接收结果要看值1和值2的类型来决定声明什么变量进行接收 String result = number1 > number2 ? "num1大于num2" : "num2大于num1"; System.out.println(result);
内存图解
1、基本数据类型的变量存的是数据 2、引用类型变量存的地址 JVM:分配 栈区 堆区 方法区 1.栈区: 存放局部变量 2.堆区: Java虚拟机中,堆是可供各个线程共享的运行时内存区域,也是供所有 类实例和数组对象 分配内存的区域,存储了被垃圾收集器所管理的各种对象。 3.方法区:方法区是可供各个线程共享的运行时内存区域 用来加载.class字节码文件(类中方法和静态方法/静态变量)是堆的逻辑组成部分
栈
局部变量:正在调用的方法中的局部变量(包括方法的参数)
生命周期 :方法调用结束时栈与局部变量一并清除
调用方法时会在栈中为该方法分配一块对应的栈帧,栈帧中存储局部变量(包括方法的参数
堆
实例对象:包括实例变量和、数组元素
实例变量:属于对象,在创建对象时存储在堆中,创建多少个对象则实例变量就会在堆中存储多少份,需要通过引用变量来访问
垃圾:没有任何引用所指向的对象
垃圾回收器(GC):不定时到堆中清理垃圾,回收过程是透明看不到的,并不一定立刻发现垃圾就立刻回收,可以通过调用system.gc()来建议虚拟机尽快调度GC来回收
内存泄漏:不再使用的对象还没被及时回收,严重时会导致系统崩溃,建议不再使用的对象要及时设置为null
方法区
.class字节码文件、静态变量、所有方法(只存一份的东西)
静态变量:属于类,在类被加载时存储在方法区中,无论创建了多少个对象,静态变量在方法区中都只存一份,常常通过类名来访问
方法:只有一份,通过this来区分具体的调用对象
数组对象存放引用类型内存图解
数组对象存放引用类型数据内存图解(多态)
数组对象存放基本类型数据内存图解
String对象创建的内存图解
流程控制
流程控制包含3种结构,任何的复杂的业务逻辑都可以通过这3种结构来实现
顺序结构
代码逐语句执行,每句必走
代码逐行执行
分支结构
有条件的执行某个语句,并非每句都走。
单路分支
双路分支
案例
/** * if--如果的意思 单路分支的使用演示类: */ public class IFDemo { public static void main(String[] args) { /** 语法结构: * if(boolean){ * //满足if条件才会执行的代码块 * } * ---------- * if(购物满500){ * 打8折的事情 * } * ---------- * 执行顺序: * 判断if小括号的boolean值 * 若为true 则执行 if小括号后面的花括号的内容 * 若为false 程序跳过if的代码块 继续往后执行. * */ //购物满500 打 8折 double price = 300;//金额 if(price >= 500){ price *= 0.8; // price = price * 0.8; System.out.println("打完8折后,应付:"+price); } System.out.println("已付款:"+price); int number = 11; if(number % 2 == 0){ System.out.println("number是偶数"); } System.out.println("代码继续往后执行..."); } } 2.双路分支 /** * 双路分支 结构的使用演示类 */ public class IFElseDemo { public static void main(String[] args) { /** 代码结构: * if(boolean){ * //满足条件所执行的代码块 1 * } else { -----else 代表否则的意思 * //不满足条件所执行的代码块 2 * } * ------------------------- * 执行过程: * 判断if小括号中的条件 * 若为true ,则执行代码块1 * 若为false,则执行代码块2 * */ // 购物满500 打8折 不满打9折 double price = 666.66; if (price >= 500) { price *= 0.8; System.out.println("打8折后应付:" + Math.round(price)); } else { price *= 0.9; System.out.println("打9折后应付:" + Math.round(price)); } System.out.println("已付款:" + Math.round(price)); //Math.round(); Java提供的四舍五入的功能,将需要四舍五入的内容放到小括号即可 } }
多路分支
if ;else if
案例
public class GuessNumber { public static void main(String[] args) { /** 多路分支的语法结构: * if(条件1){ * //条件1满足执行的代码块 * } else if(条件2){ * //条件2满足执行的代码块 * } else if(条件3){ * //条件3满足执行的代码块 * } * ........ * 执行过程: * 先判断if小括号条件1 若成立则执行条件1的代码块 ,代码跳过其他条件继续往后执行 * 若不成立 再判断条件2 若成立则执行条件2的代码块,代码跳过其他条件继续往后执行 * 若不成立 再判断条件3 若成立则执行条件3的代码块,代码跳过其他条件继续往后执行 * */ //当 我们对一个数据有多种判定条件时,可以用多路分支. /** 根据 成绩(score) 判断学生的成绩等级 * A. score >= 90 ---优秀 * B. score >= 80 && score <90 ----良好 * C. score >= 70 && score <80 ----一般 * D. score >= 60 && score <70 ----及格 * E. score < 60 -----------------不及格 * */ int score = 50;//分数 变为控制台输入获取的方式: Scanner .. if (score >= 90) { //如果分数大于等于90的话 System.out.println("优秀!"); } else if (score >= 80) {//否则如果分数大于等于80的话 System.out.println("良好!"); } else if (score >= 70) {//否则如果分数大于等于70的话 System.out.println("一般!"); } else if (score >= 60) {//否则如果分数大于等于60的话 System.out.println("及格!"); } else {//否则分数一定小于60 System.out.println("不及格!"); } /** 练习题: age * 通过控制获取数据的方式 获取用户输入的年龄,对年龄进行判定等级: * A. age>=0 && age<5 打印 幼年 * B. age>=5 && age<12 打印 少年 * C. age>=12 && age<18 打印 青年 * D. age>=18 && age<35 打印 成年 * E. age>=18 && age<50 打印 中年 * F. age>=50 && age<65 打印 中老年 * G. age>=65 && age<130 打印 老年 * 若上述条件都不成立 则打印年龄不合法 * */ Scanner s = new Scanner(System.in);//创建一个扫描器 int age = s.nextInt();//接受用户输入的数据 if(age>=0 && age<5){ System.out.println("幼年"); }else if(age >= 5 && age<12){ System.out.println("少年"); }else if(age>=12 && age<18){ System.out.println("青年"); }else if(age>=18 && age<35){ System.out.println("成年"); }else if(age>=18 && age<50){ System.out.println("中年"); }else if(age>=50 && age<65){ System.out.println("中老年"); }else if(age>=65 && age<130) { System.out.println("老年"); } else { System.out.println("年龄不合法!"); } } }
switch ..case语法结构
int a = 1; switch(a){ case 1: 匹配成功执行的代码区域 break;//代表退出当前switch整个代码块 case 2: 匹配成功执行的代码区域 break; case 10: 匹配成功执行的代码区域 break; }
案例
public class GuessNumber { public static void main(String[] args) { /** 语法结构: * int a = 1; * switch(a){ * case 1: * 匹配成功执行的代码区域 * break;//代表退出当前switch整个代码块 * case 2: * 匹配成功执行的代码区域 * break; * case 10: * 匹配成功执行的代码区域 * break; * } * */ Scanner s = new Scanner(System.in); System.out.println("请根据业务提示:1.存款 2.取款 3.转账"); int command = s.nextInt();//接受用户输入的执行 switch (command){ case 1: System.out.println("正在办理存款业务"); break;//退出的switch结构 若不写break,则还会继续执行后面的语句(则不看case) case 2: System.out.println("正在办理取款业务"); break; case 3: System.out.println("正在办理办理转账业务"); break; default: System.out.println("指令不合法!"); } System.out.println("代码逐语句往后执行...."); } }
循环结构
有条件的重复执行某个语句,并非每句都走 循环的语法的三要素: 1. 循环变量的初始化 2.基于循环变量的一个条件 3.循环变量的改变(朝着目标去改变)
while(条件boolean) {循环体}
经典案例【弹弹球】
public class GuessNumber { public static void main(String[] args) { double height = 100; int count = 0; double distance = height; while (height / 2 > 0.01) { height /= 2; distance += height * 2; count++; } System.out.println("总共弹起" + count + "次"); System.out.println("总共经过" + distance + "米"); } }
do{循环体}while(boolean);
经典案例
//猜数字然后提示小了还是大了 public class GuessNumber { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int user; int guess = (int)(Math.random() * 100); do { System.out.println("请猜数字,范围是(0~100)" +guess); user = scanner.nextInt(); if (user<guess) { System.out.println("猜小了"); } else if (user>guess) { System.out.println("猜大了"); } } while(user != guess); System.out.println("猜中了"); } }
while和do whlie的区别
while是先判断,有可能一次循环都不做,而do while是先做循环,至少做一次,在进行判断 do { } while(); while() { }
for(应用率更高)
嵌套for循环
经典案例
99乘法表 public class ForDemo02 { public static void main(String[] args) { for (int i=1;i<=9;i++) { for (int j=1;j<=i;j++) { System.out.printf("%d * %d = %d\t", j,i,i*j); } System.out.println(); } } }
面向对象
类概念
是抽象的概念集合,表示的是一个共性的产物,类之中定义的是属性和行为(方法)
属性/变量
成员变量
成员变量有默认值,例如 int a;sout.a时打印 0 局部变量没有默认值,必须先声明,赋值后才能使用
局部变量
凡是在方法里面定义的都叫局部变量(包括形参)
当调用方法时形参和实参不是同一个变量,而是两个不同的变量,传递过程中是把实参赋值给形参
实例变量
对象中的变量:在船时存储在堆中,对象被回收时一并回收
静态变量
static修饰的变量和方法会在程序main方法之前存在即在对象之前存在,所以不能new,而且有且只有一份 2、当局部变量和成员变量同名且成员变量为静态,在方法里使用该同名变量时,,遵循就近原则,优先默认调用局部变量
扩展
final修饰的变量
不可变的变量
static final修饰的常量
必须声明的同时初始化,类名点来访问,不能改变,名字全部大写,多个单纯词_分割
成员/实例方法
方法又称之为函数,主要就是用来表示功能(行为) 1、方法中的this,那个对象调用这个方法,this就表示哪个对象
语法结构:[访问修饰符] 返回值 方法名([参数列表]) {方法体}
无参无返回
package day07; public class MethodDemo1 { public static void main(String[] args) { say(); } /** * 无参无返回 * 无参有返回 * 有参无返回 * 有参有返回 * */ static void say() { System.out.println("11"); System.out.println("22"); System.out.println("33"); } }
无参有返回
public class tmp { String name = "张三"; String haha() { return name; } public static void main(String[] args) { tmp t = new tmp(); System.out.println(t.haha()); } }
有参无返回
有参有返回
构造器(又叫构造函数、构造方法)
1、创建对象的时候,构造方法会随之执行,不能有返回值,构造器也是方法,也可以进行方法重载 构造方法的名称必须和类名一样,不允许使用return返回值,但是可以单独使用return,进行结束方法 2、编写一个类,系统会默认赠送一个无参的构造函数 例如 class Test { Test() { } }
有参构造方法
生产环境中,如果写了有参构造方法,把无参构造方法也跟上
案例
那什么时候会用到this这个东西?参数名和成员变量一样的时候 package oo.day01; public class Student { String name; int age; String studentId; void syaHi() { System.out.printf("我叫%s,今天%d岁,学号%s\n",name,age,studentId); } void eat() { System.out.println(name + "可劲造。。。。。。。。。。。"); } void study() { System.out.println(name + "在学习"); } // 构造器,创建对象的时候被自动执行 Student(String name,int age,String studentId) { this.name = name; //构造器的参数和成员变量的name一样时候,需要在前面加this this.age = age; this.studentId = studentId; } }
无参构造方法
案例
package oo.day01; public class Student { String name; int age; String studentId; void syaHi() { System.out.printf("我叫%s,今天%d岁,学号%s\n",name,age,studentId); } void eat() { System.out.println(name + "可劲造。。。。。。。。。。。"); } void study() { System.out.println(name + "在学习"); } // 构造器,创建对象的时候被自动执行 Student() { this.name = "张三"; //无参构造器 this.age = 18; this.studentId = "x001"; } }
重载
1、在一个类中,存在多个同名的方法,这些个方法参数类型不一样,参数个数不一样,在调用对象方法的时候会出现重载 2、重载的概念是: 1、方法名称相同,参数个数、次序、类型不同 2、不在意访问权限和返回值 PS:如果参数的个数、类型、次序都相同,方法名也相同,仅返回值不同,则无法构成重载
案例
package oo.day01; public class Student { String name; int age; String studentId; void syaHi() { System.out.printf("我叫%s,今天%d岁,学号%s\n",name,age,studentId); } void eat() { System.out.println(name + "可劲造。。。。。。。。。。。"); } void study() { System.out.println(name + "在学习"); } // 构造器,创建对象的时候被自动执行 Student(String name,int age,String studentId) { this.name = name; this.age = age; this.studentId = studentId; } Student() { } //构造方法也是方法的一种,也会有重载的时候,实现创建对象的时候,可以指定实参,也可以不指定 } 还有一种情况就是子类继承父类,方法名一样,但是参数和参数类型不同,发生的是重载 class Fu { void run() { System.out.println("jaja") } class Zi extends Fu { void run (int i) { System.out.println(i) } }
方法重写/覆盖Override
错误的分类/异常处理
1.编译错误:编译期产生的错误----全部都是语法错误 (欠练!)
2.运行异常:运行期产生的错误----空指针异常/数组下标越界异常
3.程序不报错,呈现的现象跟你设计的现象不一样。
静态方法
1、没有多态的特性,如果发生向上造型,调用静态方法,直接看申明的类型 2、静态方法不可以调非静态全局变量,从内存的角度看,就是当类被加载的时候静态方法和静态属性(全局静态变量)被加载到内存中,就是在内存中开辟一段内存地址用来保存静态方法和静态属性,这时候没有被实例化的类在内存中是不存在的,所以静态方法是不能访问非静态的全局变量。在类被实例化的时候,就是new 某个类的时候,在内存中给这个类开辟一些内存空间保存这个类的对象,这个时候就可以用静态方法去访问非静态的全部变量。
有坑的案例
class A { static void m1() { System.out.println("m1 in A"); } void m2() { System.out.println("m1 in A"); } } class B extends A { static void m1() { System.out.println("m1 in B"); } @Override void m2() { System.out.println("m2 in B"); } } class Test { public static void main(String[] args) { A s = new B(); s.m1(); //static方法看声明类型 s.m2(); //发生多态现象,声明父类,执行子 B b = (B)s; b.m1(); //向下转型,静态看声明类型,是B,那就是B类中的m1方法 b.m2(); } } m1 in A m2 in B m1 in B m2 in B
代码块
用一对{}包住的内容就是代码块
构造代码块
1)在类的内部、方法的外部 2)每次调用构造方法时候,会先调用构造代码块,在执行构造方法 3)当一个类的多个构造方法具有相同的代码时候,为了避免代码冗余,可以放在构造代码块中执行 class Person{ { System.out.println("你好"); } Person() { System.out.println("无参构造函数被调用了"); } Person(String name) { System.out.println("有参构造函数被调用了"); } } public class Student { public static void main(String[] args) { Person p1 = new Person(); Person P2 = new Person("张三"); } } 
静态代码块
1.由static修饰的代码块,称之为静态代码块。 2.属于类,当类被加载时(当第一次用到某个类时,类且只加载一次),静态代码块则会被只执行一次。 3.如果类被创建对象时,那么优先调用静态代码块,再调用该类的构造方法(在构造方法之前) 4.也可以直接通过访问类的静态成员 达到加载的方式。
局部代码块
1)在方法内部 2)通常用于控制变量的作用范围,处理{}就失效了 3)变量的范围越小越好(比如成员变量是整个类的,可能存在线程安全问题) public class Student { public static void main(String[] args) { Person p1 = new Person(); Person P2 = new Person("zhangsan"); int i = 1; for (;i<=10;i++) { System.out.println(i); } System.out.println(i); } } 如果是 for(int i=1;i<=10;i++) { System.out.println(i); //只能看到i等于10,但是实际i已经是11了,这时候的i只能在for循环中使用,处理{},就访问不到了 }
扩展
Object类s
Object类:是类继承关系中的根类(最顶层的类),所有的类都直接或间接继承自Object类 1、自定义类的父类是Object类,默认带有它的一些方法,equals、toString等
常用方法
int hashCode() -- 返回该对象的哈希码值(int值)。 String toString() -- 返回对象的字符串表示形式,建议所有子类重写该方法(自动生成即可) boolean equals(Object obj) -- 比较对象是否相等,默认比较地址,重写可以比较内容,建议所有子类重写该方法(自动生成即可)
package
如果仅仅类名是唯一标识的话,很有可能类名发生冲突。 1000个类 想1000个类名,所以Java设计package 作用:避免类名的冲突 现象:同包中的类名是不能冲突的,不同包类名没有冲突。s 包名:包名纯小写。 银行项目上亿.... 域名反写.项目名称.模块名.类名
import
访问其他包的类
三大特征
封装
类封装
封装同一类别下所有对象共有的属性的行为
属性封装
将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象的内部信息,而是通过类提供的方法进行内部信息的访问和操作。 package oo.day01; public class Student { private String name; private int age; private String studentId; void syaHi() { System.out.printf("我叫%s,今天%d岁,学号%s\n",name,age,studentId); } void eat() { System.out.println(name + "可劲造。。。。。。。。。。。"); } void study() { System.out.println(name + "在学习"); } // 构造器,创建对象的时候被自动执行 Student(String name,int age,String studentId) { this.name = name; this.age = age; this.studentId = studentId; } public void setName(String name) { this.name = name; } public String getName() { return name; } Student() { } }
属性私有化,方法公开化 (目的:保护程序(属性)防止任意地方修改!)
方法封装
封装某个功能逻辑,达到复用(一次定义,多次使用)
继承
好处:实现代码的复用 坏处:耦合性高!(父类只放子类共有的属性和行为)
子类中的所有构造函数都会默认的去访问父类的无参构造
父类的private方法和变量不能被继承
重写
发生在父子类中,方法名相同,参数列表相同,即为重写。并且重写还需要遵循另外的两小一大原则,其中的一大指的是派生类方法的访问权限必须大于或等于超类方法的, 两小指的是派生类方法的返回值类型要小于或等于超类方法的,派生类方法抛出的异常要小于或等于超类方法的。 父类引用子类对象如果不重写共性的方法,默认是调用父类的方法,这显然不合理,子类是具体的类,有自己的属性,这里就引进了重写 Fu f = new Zi() 如果不重写共性方法,那执行的是父类中的方法
需要遵循的规则
两同
1、方法名相同 2、 参数列表要相同。
两小
1、子类在重写父类方法时,返回值类型要等于或小于父类中那个方法 2、子类在重写父类方法时,异常要等于或小于父类中的那个方法 (异常第二阶段)
一大
子类在重写父类方法时,访问权限要等于或大于父类中那个方法
final修饰的方法不能重写
重载
方法名相同, 参数列表不同,称为方法的重载
方法的重载与返回值类型无关、与参数名称也无关。
作用:代码复用 超类:所有派生类的共有行为 接口:派生类的部分行为
多态
在一个类别下 的不同实现 声明父 new 子 子类不同实现!
三个条件
1、要有继承关系
条件一:要有继承关系 ----------------------------------------------- class Animal{ public void call() { System.out.println( "动物在叫..." ); } } class Dog extends Animal{ }
2、子类重写父类方法
条件二:要有方法重写 ----------------------------------------------- class Animal{ public void call() { System.out.println( "动物在叫..." ); } } class Dog extends Animal{ public void call() { //重写父类的call方法 System.out.println( "狗在汪汪汪的叫..." ); } } 重写需要遵循两同两小一大 1、方法名相同;参数列表要相同 2、两小:返回值类型要等于或小于父类中那个方法;子类在重写父类方法时,异常要等于或小于父类中的那个方法 3、子类在重写父类方法时,访问权限要等于或大于父类中那个方法。
3、父类引用指向子类对象
条件三:要有父类引用指向子类对象 ----------------------------------------------- 只能使用父类存在的方法给你 class Fu{ public void run() { System.out.println("Fu.run 运行了。。。"); } } class Zi extends Fu{ public void run() { System.out.println("Zi.run 运行了。。。"); } public void fuck() { System.out.println("fuck方法执行了。。。"); } } Fu f1 = new Zi(); f1.run();
对象多态
同一个引用类型指向不同的对象时,有不同的实现
同一个对象被造型为不同的类型时,有不同的功能
强转成功的条件
引用指向的对象就是该类型(instanceof)
引用指向的对象实现了该接口或继承来该类型
方法多态
向上造型
超类的引用指向派生类的对象(前面是超类,后面是派生类型)
能点出来什么,看引用类型
能向上造型的类型:超类+所实现的接口
SeaObject o = new Batlesjip(); o 只能点出 SeaObject;类中的方法和属性,向上造型后,只能点出来SeaObject中的 强转后才可以使用Batleshio的方法和属性 public class MultiTyp { public static void main(String[] args) { Aoos o= new Boos();//向上造型 Inter o2 = (Inter) o;// Coos o3 = (Coos)o;//运行时会发生ClassCastException类型转换异常 // if ( o instanceof Coos){ Coos o4 = (Coos) o; } } } interface Inter{} class Aoos{} class Boos extends Aoos implements Inter{} class Coos extends Aoos{}
instanceof 关键字判断是否我相同类型的对象
强制类型转换成功的两个条件
引用所指向的对象就是该类型
引用所指向的对象得实现了该接口或继承了该类
好处
提高代码的维护性
提高代码的扩容性
精简代码
出现多态,可以定义一个工具类,接受形参为父类引用类型,实参可以指向子类对象,实现代码的精简 class Animal{ public void eat() { System.out.println("Animal.eat()"); } public void sleep() { System.out.println("Animal.sleep()"); } public void play() { System.out.println("Animal.play()"); } } class Dog extends Animal{ public void eat() { System.out.println("狗吃肉..."); } public void sleep() { System.out.println("狗蹲着睡觉..."); } public void play() { System.out.println("狗玩骨头..."); } } class Cat extends Animal{ public void eat() { System.out.println("猫吃鱼..."); } public void sleep() { System.out.println("猫趴着睡..."); } public void play() { System.out.println("猫玩毛线..."); } } class AnimalTool{ public static void runAnimal( Animal a ) { a.eat(); a.sleep(); a.play(); } }
弊端的完美规避
向下转型
父类引用类型变量接受子类对象,但是一定要用子类中特有的属性(成员变量和方法) Fu f = new Zi() Zi z = (Zi) f
1、子类方法和父类方法但可以使用
向上造型
父类引用子类对象的过程称为向上造型 Fu f = new Zi()
1、编译期间调用的是父类的方法,取决于引用类型 2、运行时的调用的方法取决于当前对象 3、不能访问子类的方法
code demo
public class Test { public void FuPint(){ System.out.println("父类"); } public static void main(String[] args) { Test test = new Test1(); test.FuPint(); // test.ZiPint(); //报错 Test1 test1 = (Test1) test; test1.FuPint(); test1.ZiPint(); } } class Test1 extends Test{ public void ZiPint(){ System.out.println("子类"); } } "C:\Program Files\Java\jdk1.8.0_231\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.3.4\lib\idea_rt.jar=61122:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.3.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_231\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\rt.jar;D:\TEDU\Desktop\yangmufa\Projects\work0618_杨木发\out\production\work1" main.Test 父类 父类 子类 Process finished with exit code 0
扩展
包装类和基本数据类型
八个基本数据类型都有各自的包装类 弥补了基本类型不具备对象的可操作性缺点 - java定义了8个包装类,目的是为了解决基本类型不能直接参与面向对象开发的问题,使得基本类型可以通过包装类的形式存在。 - 包含:Integer、Character、Byte、Short、Long、Float、Double、Boolean。其中Character和Boolean是直接继承Object类的,而其余6个包装类继承自java.lang.Number类。 - JDK1.5推出了一个新的特性:自动拆装箱。当编译器编译时若发现是基本类型与包装类型相互赋值,将自动补充代码来完成转换工作,这个过程称为自动拆装箱。
byte 1字节
Byte(Number的子类)
boolean 1字节
Boolean(直接继承Object)
short 2字节
Short(Number的子类)
char 2字节
Character(直接继承Object)
float 4字节
Float(Number的子类)
int 4字节
Integer(Number的子类)
package APIday03; public class InteagerDemo { public static void main(String[] args) { Integer i1 = new Integer(5); Integer i2 = new Integer(5); System.out.println(i1==i2);//false == 比较的是地址 //Integer.valueOf会复用-127到128范围内的数据(类似于常量池),建议使用value的方式 Integer i3 = Integer.valueOf(5); Integer i4 = Integer.valueOf(5); System.out.println(i3==i4);//teue //触发自动装箱的特性,会被被编译为:Integer i = Integer.valueOf(5) Integer i = 5; //触发自动拆箱特性,会被编译为:int j = i.valueOf(); int j = i;//包装类型到基本类型--拆箱 //包装类常用操作 //1、可以同包装类来得到基本类型的取值范围 int max = Integer.MAX_VALUE;//获取int 的最大值 int min = Integer.MIN_VALUE;//获取int 的最小值 System.out.println("int 的最大值:"+max+",最小值:"+min); long Lmax = Long.MAX_VALUE;//获取long 的最大值 long Lmin = Integer.MIN_VALUE;//获取long 的最小值 System.out.println("Long 的最大值:"+Lmax+",最小值:"+Lmin); //包装类型可以将字符串转换为对应基本类型 int age = Integer.parseInt("666"); System.out.println(age);// pint:int 666 double d = Double.parseDouble("999.789"); System.out.println(d); } } pint: false true int 的最大值:2147483647,最小值:-2147483648 Long 的最大值:9223372036854775807,最小值:-2147483648 666 999.789
double 8字节
Double(Number的子类)
long 8字节
Long(Number的子类)
扩展
BigInterger
Bigdecimal
为了让超过int或者double的数值运算的结果能正常输出,也是为了提高精度,因为double的运算是存在误差的
匿名内部类
匿名内部类(应用率高) 没有名字的内部类叫做匿名内部类. 适用性:如果一个子类,仅仅只是想重写实现父类中某个方法时,其他地方也根本用不到这个子类,那么我们可以直接使用匿名内部类的方式,快速实现重写的逻辑! 1.匿名内部类只会存在于子类要重写父类的(抽象/普通)方法时,才会用到. 2.匿名内部类 无法修改外部类的值!因为规定在匿名内部类的类体中使用外部类的属性时,会自动修饰为final public class NsInnerClassDemo { public static void main(String[] args) { int b = 10; // b=20; Aoo aoo = new Aoo(){ @Override public void show() { System.out.println("匿名内部类重写Aoo的show方法"); System.out.println(b); } }; aoo.show(); Aoo aoo1 = new Aoo() { @Override public void show() { System.out.println("匿名内部类重写Aoo的show方法2"); } }; aoo1.show(); } } class Aoo { public void show() { System.out.println("Aoo父类的show方法"); } } 对于内部类的aoo和aoo1来说,外部类的是用final修饰过的,因此如果匿名内部类中使用了外部类的成员变量,这个成员变量不能进行二次赋值,否则报错
什么时候用呢,子类继承父类,但是这个子类不需要被别人调用,可以采用匿名内部类的方式,重写父类中的方法并进行调用
成员内部类
成员内部类(应用率不高) 类中套个类,外层的类称之为外部类,内层的类称之为内部类 1.内部类除了对外层类 以外不具备可见性 2.内部类对象 可以在外层类创建 3.内部类共享外部类的属性和行为 (包括私有) 4.内部类访问外部类 隐式写法 类名.this.xx 内部类可以访问外部类的属性,并且可以修改,匿名内部类就不行
类中套类,里面一层成为内部类,外面一层称为外部类
内部类只服务于外部类,且不具有可见性
内部类对象通常在外部类中创建
内部类可以直接访问外部类的成员(包括私有的)
内部类中有一个隐式的引用他指向创建他的外部类对象(外部类名.this)
外部类可以直接访问内部类
隐式引用:
this:指代当前对象
super:指代当前对象的超类对象
外部类名.this:指代当前对象的外部类对象
内部类的class文件命名为:外部类名$内部类名.class
设计设计原则
先写行为方法
若某个对象所特有的方法就设计在特定的类中
若为对象所共有的行为功能就设计在超类中
调用窗口
若为定时发生的就在定时器中调用
若为事件触发就在侦听器中调用
面试题
成员内部类: 外部类的类名 字节码文件 成员内部类 内部类的字节码文件 Mama Mama.class Mama.Baby Mama$Baby.class class Mama{//外部类 -- private int a; void action(){ Baby b = new Baby();//外部类可以创建内部类对象 } class Baby{//内部类 int c; void test(){ this.c = 100;//隐式this的传递 代表自己的东西 Mama.this.a = 10;//内部类可以共享外部类的属性和行为 隐式写法类名.this.xx Mama.this.action(); } } } 匿名内部类: 外部类的类名 字节码文件 匿名内部类的字节码文件 NsInnerClassDemo NsInnerClassDemo.class NsInnerClassDemo$1.class public class NsInnerClassDemo { public static void main(String[] args) { int b = 10; //使用匿名内部类的方式: //1.创建Aoo的子类 只不过没有名字 //2.将当前这个没有子类对象 地址 赋值给了 a //3.花括号就是子类的类体! Aoo a = new Aoo() { //创建的匿名内部类的外部类是NsInnerClassDemo这个类 //创建的匿名内部类的父类是 Aoo这个类 @Override public void show() { // b = 100; 匿名内部类无法修改外部类的属性的 // System.out.println(b); 匿名内部类使用外部类属性会默认为 final System.out.println("匿名内部类重写Aoo的show方法"); } }; a.show(); //常规的重写 // Boo b = new Boo(); // b.show(); } } class Aoo { //-----作为父类 public void show() { System.out.println("Aoo这个父类的show方法"); } } //常规的重写 class Boo extends Aoo { //构建父子关系 @Override public void show() { System.out.println("Boo子类重写父类的show方法"); } }
匿名内部类
若想创建一个类(派生类)且对象只创建一次时设计为匿名内部类能大大简化代码操作
在匿名内部类中不能修改外面局部变量的值,因此在此处该变量会默认为 final
Aoo o = new Aoo{}; 即发生了向上造型,new Aoo{}为派生子类
创建含有抽象方法的匿名内部类时需要重写抽象方法
匿名内部类的class文件没有真实名字而是用1、2、3、来命名:外部类名$1.class
抽象方法
abstract修饰,只有方法的定义,没有具体的实现(没有方法体)
抽象类
abstract修饰 抽象类中可以有抽象方法,也可以有非抽象方法 子类作为具体类继承抽象的父类,必须重写所有父类中的抽象方法 非抽象方法能直接被继承的子类直接调用
抽象类不能直接 new
abstract修饰,包含抽象方法的类必须是抽象类,抽象类不能被实例化, 需要被继承,
抽象类的意义: 1、封装共有的属性和方法,为所有派生类提供统一的类型 2、可以包含抽象的方法,为是所有的派生类提供统一的入口(能点出来) 3、强制派生类必须重写方法,如果一个类中没有抽象方法也可以设计为抽象类,
接口
接口: 接口是一组行为的规范,接口不关心多个具体实现类之间是否是一种的关系,关注它们的行为是否达到统一。 一旦实现(子)类 实现了 接口,那么必须要实现该接口中所有的行为。所以往往在设计时候,接口一般只放一个功能。(定义小而精的接口) 1.接口是一种数据类型(引用类型) 2.用interface 进行定义,代表接口。 3.接口中只能放常量 和抽象方法。接口中不管是常量还是抽象方法 默认访问权限都是公开的! 4.接口是不能被创建对象的。 5.接口是需要被实现类/子类 实现的。一旦实现(子)类 实现了 接口,那么必须要实现该接口中所有的行为。 6.一个类是可以实现多个接口的!实现时需要通过 implements 来实现,在后面写上接口名即可。 若一个子类又继承了一个父类 又想实现接口,子类 extends 父类名 implements 接口名 7.接口与接口之间 是可以继承的!例如:B接口 继承了 A接口,但是 C类 若实现了B接口,那么C同时还要实现A接口中的抽象内容。
interface修饰
1、只能包含 常量、抽象方法 2、访问权限全部public 3、不能被实例化只能被实现 4、一个接口单独出现没有意义,一个类可以同时实现多个接口用逗号分隔 5、接口的方法必须被实现类全部重写(重写方法时需显示的写明大于或等于接口访问权限) 6、可以又继承(实类和抽象类)又实现(先继承后实现)
部分共有用抽象,全部共有用继承
接口是对继承的单根性拓展即实现多继承
一个接口可以继承多个接口
和抽象类的区别
instanceof
1、实例 instanceof 引用类型 2、实例 instanceof 接口 class A { } class B extends A { } interface C { } class D implements C { } class Test { public static void main(String[] args) { A a = new B(); D d = new D(); if (d instanceof C ) { System.out.println("ce"); } if (a instanceof B) { System.out.println("shi"); } if (a instanceof A) { System.out.println("instance"); } } }
String
package APIday01; public class StringDemo { public static void main(String[] args) { String s1 = "123abc"; String s2 = "123"+"abc"; System.out.println(s1==s2); System.out.println(s1.equals(s2)); String s3 = "123"; String s4 = s3+"abc"; System.out.println(s1==s4); System.out.println(s1.equals(s4)); String s5 = new String("yangmufa"); String s6 = "yangmufa"; System.out.println(s5==s6); System.out.println(s5.equals(s6)); } } pint: true true false true false true
lang.language包下
final的不能被继承
底层是个char数组
字符串是不可变的(重新复用则会指向新的对象)
常量池(堆中):
复用:当使用相同字面量再创建对象时将会复用常量池中的对象以减少内存的开支
String字符串直面量的对象才会存入常量池(字面量:String s1 =“wohaoshuai”,s2 =s1+"EE" 不是直面量不会存入常量池)
String s = new String("hello") 的方式创建时会有两个对象即 “hello”字面量对象 和 字符串常量池
String s1 = "hello" 直面量的方式创建时会复用常量池的对象
== 比较的是内存地址,equals比较的是内容
method
.length() 字符串或数组长度(包含空格)
package APIday01; public class LengthDemo { public static void main(String[] args) { String str = "我爱Java"; int len =str.length(); System.out.println(len); } } pint:6
.trim() 去除字符串两边的空格
package APIday01; public class TrimDemo { public static void main(String[] args) { String str = " hello world"; System.out.println(str=str.trim());//去除两边的空格 System.out.println(str); } } pint: hello world hello world
toUpperCase() toLowerCase() 将当前字符串中的英文字母转换为大写和小写
package APIday01; /** * toUpperCase()将当前字符串中的英文字母转换为大写 * toLowerCase()将当前字符串中的英文字母转换为大写 */ public class ToUpperCaseDemo { public static void main(String[] args) { String s1 = "燕子 I Love You"; System.out.println(s1.toUpperCase());//转大写 System.out.println(s1.toLowerCase());//转小写 } } pint: 燕子 I LOVE YOU 燕子 i love you
boolean startsWth(String s) boolean endsWith(String s) 判断是否以 "XX" 开头 和 结尾
package APIday01; /** * boolean startsWth(String s) 判断是否以 "XX" 开头 * endsWith(String s) 判断是否以 "XX" 结尾 * */ public class startsWith { public static void main(String[] args) { String s1 = "燕子 You Don't Go"; String str = "thinking in 珍珍"; boolean starts = s1.startsWith("燕子"); System.out.println(starts); System.out.println(str.endsWith("珍珍")); } } pint: true true
char charAt() 根据小标索引返回对应的字符(包含空格)
package APIday01; /** * char charAt() * 根据小标索引返回对应的字符(包含空格) * * * */ public class CharAtDemo { public static void main(String[] args) { String str = "thinking in java"; System.out.println(str.charAt(9)); } } pint:i
int indexOf() int lastIndexOf() 检索给定字符串在当前字符串的最前位置的下标 和 最后出现位置的下标 检索到返回对应的下标否则返回-1
package APIday01; /** * int indexOf() 检索给定字符串在当前字符串的开始位置----根据字符串找对应的位置 * int lastIndexOf() 检索给定字符串在当前字符串的最后位置----根据字符串找对应的位置 * 找不到 返回 -1 */ public class IndexAtOfDemo { public static void main(String[] args) { String str = "thinking in java"; System.out.println(str.indexOf("in")); //从小标位置为3的地方开始查找 System.out.println(str.indexOf("in",3));//重载 System.out.println(str.indexOf("wohaoshuai"));// -1 System.out.println(str.lastIndexOf("in")); } } pint:| 2 5 -1 9
String substring(int start,int end) 截取当前字符串中指定范围内的字符串(含头不含尾,包含start不包含end) String substring(int start) 直接截取开始到最后
package APIday01; /** * String substring(int start,int end) * 截取当前字符串中指定范围内的字符串(含头不含尾,包含start不包含end) * String substring(int start) * 直接截取开始到最后 */ public class SubStringDemo { public static void main(String[] args) { String str = "www.tedu.cn"; System.out.println(str.substring(4,8));//截取下标4-7范围的字符串 System.out.println(str.substring(4));//截取 4到最后的字符串 } } pint: tedu tedu.cn
static String valueOf(数类型 a) 将其他数据类型转换为String 遇到字符串拼接后变为字符串
package APIday01; import static java.lang.Character.getType; /** * static String valueOf(数类型 a) * 将其他数据类型转换为String */ public class valueOfDemo { public static void main(String[] args) { int num = 666; System.out.println(String.valueOf(num));//得到字符串 System.out.println(num+"ber");//遇到字符串拼接后变为字符串 } }
StringBuilder
维护了一个可变数组相较于String大大提高了性能 非线程安全的,并发处理,性能好
package APIday01; /** * String and StringBuilder * StringBuilder是专门用于修改字符串的一个类,内部维护了一个可变数组,且包含String的方法 * 所做修改都是咋这个数组上进行的,修改速度非常优秀。并且还提供了修改字符串的常用方法: * append:增 * delete:删 * replace:改 * insert:插 */ public class StringBuilderDemo { public static void main(String[] args) { // String a = "a";//维护不可变的数组 // for (int i = 0; i < 100000; i++) {//10W次 // a += i;//每次修改都会创建新的对象, 效率低下 执行完需要5分钟 // } // System.out.println("over"); String s1 = "abc"; StringBuilder builder1 = new StringBuilder();//空字符串 StringBuilder builder2 = new StringBuilder("abc");//abc字符串 StringBuilder builder3 = new StringBuilder(s1);//abc字符串 //将builder3转换为String类型 String s3 = builder3.toString(); System.out.println(s3); String str = "为祖国的伟大事业,"; //复制str的内容到builder中 StringBuilder builder = new StringBuilder(str); System.out.println(builder); //append:追加 (含头不含尾) builder.append("添砖Java"); System.out.println(builder); //replace:替换、插入 (含头不含尾) //把11~11之间的内容删除,然后插入"加瓦," builder.replace(11,11,"加瓦,"); System.out.println(builder); //delete:删除部分内容 (含头不含尾) builder.delete(11,14);//删除 "加瓦," System.out.println(builder); //insert:插入内容 (含头) builder.insert(15,",山东-菏泽-曹县 牛皮pulasi双击666"); System.out.println(builder); String b = "a"; StringBuilder sb = new StringBuilder(b);//维护了可变数组 for (int i = 0; i < 100000; i++) {//10W次 sb.append(i);//每次修改都是在原数组追加,执行完只需要2秒 } System.out.println("builderOver"); } } pint: abc 为祖国的伟大事业, 为祖国的伟大事业,添砖Java 为祖国的伟大事业,添砖加瓦,Java 为祖国的伟大事业,添砖Java 为祖国的伟大事业,添砖Java,山东-菏泽-曹县 牛皮pulasi双击666 SB over
StringBuffer
线程安全的,同步处理,性能较慢
Object
Java Object 类位于 java.lang 包中是所有类的父类,Java 的所有类都继承了 Object,子类可以使用 Object 的所有方法,编译时会自动导入,创建一个类时如没有明确父类,那么它会自动继承(隐式继承) Object,成为 Object 的子类
package APIday02; import APIday01.startsWith; /** * 输出引用变量时默认会调用Object类的toString()方法 * 方法返回字符串格式为:类的全称@地址 * 但是这个返回结果对我们不要帮助 * 因此常常需要重写toString(),返回我们自己想要的数据 * 一旦Point类重写了toString()则会调用重写之后的java中的String、StringBuilder等 * 已重写toString的方法 */ public class ObjectDemo { int x=0; public static void main(String[] args) { Point point = new Point(6,9); //输出引用变量时默认调用point发父类(Object)的toString方法 System.out.println(point); /** * 调用Object类的equals(),内部还是调用 == 来比较内存地址, * 若想比较对象的属性值是否相同需要重写父类(继承类或Object类)equals方法 */ System.out.println(new Point(6,9)==new Point(6,9));//false System.out.println(new Point(6,9).equals(new Point(6,9)));//false,重写equals方法后为 true // //new对象,创建匿名内部类,调用toString方法 // new startsWith().toString();{ // System.out.println("珍珍"); // }; StringBuilder builder1 = new StringBuilder("hello"); StringBuilder builder2 = new StringBuilder("hello"); System.out.println(builder1.equals(builder2)); StringBuilder builder3 = new StringBuilder("hello"); } } pint:Point{x=6, y=9} false true false
正则
描述字符串内容格式, 用于匹配一个字符串的内容是否符合格式要求
package APIday03; public class InteagerDemo { public static void main(String[] args) { Integer i1 = new Integer(5); Integer i2 = new Integer(5); System.out.println(i1==i2);//false == 比较的是地址 //Integer.valueOf会复用-127到128范围内的数据(类似于常量池),建议使用value的方式 Integer i3 = Integer.valueOf(5); Integer i4 = Integer.valueOf(5); System.out.println(i3==i4);//teue //触发自动装箱的特性,会被被编译为:Integer i = Integer.valueOf(5) Integer i = 5; //触发自动拆箱特性,会被编译为:int j = i.valueOf(); int j = i;//包装类型到基本类型--拆箱 //包装类常用操作 //1、可以同包装类来得到基本类型的取值范围 int max = Integer.MAX_VALUE;//获取int 的最大值 int min = Integer.MIN_VALUE;//获取int 的最小值 System.out.println("int 的最大值:"+max+",最小值:"+min); long Lmax = Long.MAX_VALUE;//获取long 的最大值 long Lmin = Integer.MIN_VALUE;//获取long 的最小值 System.out.println("Long 的最大值:"+Lmax+",最小值:"+Lmin); //包装类型可以将字符串转换为对应基本类型 int age = Integer.parseInt("666"); System.out.println(age);// pint:int 666 double d = Double.parseDouble("999.789"); System.out.println(d); } }
matches() 使用给定的正则表达式(regex)验证当前字符串的格式是否符合要求, 符合则返回true,否则返回false
package APIday02; import javax.crypto.spec.PSource; /** * boolean matches(String regex) 匹配 * 使用给定的正则表达式(regex)验证当前字符串的格式是否符合要求,符合返回true,否则返回false */ public class MatchesDemo { public static void main(String[] args) { //邮箱正则:[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\.[a-zA-Z]+)+ String email = "email@muyiafa.com"; // \. 一个杠表示正则中的转义, \\. 两个杠表示Java中的转义 String regex = "[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\\.[a-zA-Z]+)+"; //使用regex匹配email是否符合该正则的格式要求 if (email.matches(regex)){ System.out.println("是 一个正确的邮箱格式"); }else System.out.println("不是 一个正确的邮箱格式"); } }
replaceAll() 将当前字符串中满足正则表达式(regex)的部分给替换为给定的字符串(s)
/** * String replaceAll(String regex,String s):替换 * 将当前字符串中满足正则表达式(regex)的部分给替换为给定的字符串(s) */ public class ReplaceAllDemo { public static void main(String[] args) { String line = "abc123def456ghi78"; //将line中的数字部分替换为#NUMBER# line = line.replaceAll("[0-9]+","#NUMBER#"); System.out.println(line); } }
split() 将当前字符串按照满足正则表达式的部分进行拆分,并将拆分出的以String[]形式来返回
import java.util.Arrays; /** * String[] split(String regex):拆分 * 将当前字符串按照满足正则表达式的部分进行拆分,并将拆分出的以String[]形式来返回 */ public class SplitDemo { public static void main(String[] args) { String line = "abc123def456ghi"; String[] data = line.split("[0-9]+"); //按数字拆分(数字就拆没了) System.out.println(Arrays.toString(data)); //将data数组按String格式输出 line = "123.456.78"; data = line.split("\\."); //按.拆(.就拆没了) System.out.println(Arrays.toString(data)); //最开始就是可拆分项(.),那么数组第1个元素为空字符串------------"" //如果连续两个(两个以上)可拆分项,那么中间也会拆出一个空字符串----"" //如果末尾连续多个可拆分项,那么拆出的空字符串被忽略 line = ".123.456..78......."; data = line.split("\\."); //按.拆(.就拆没了) System.out.println(Arrays.toString(data)); } }
进制
二进制
权:128 64 32 16 8 4 2 1
规则:逢二进一
数字:0 1
基数:2
转十进制:把各按权位为1的数相加
直面量前缀:0b(可以用下划线隔开) int n = 0b1011_1001_0011(二进制)
package cn.tedu; public class HexDemo { public static void main(String[] args) { System.out.println(0b1011_1001_0011); } } pint:2963
Integer.BinarytoString(int) Long.BinarytoString(int) 把int转为二进制输出
八进制
权:512 64 8 1
规则:逢八进一
基数:8
数字:0 1 2 3 4 5 6 7
转十进制:把各按权位不为0的数相加
直面量前缀:0 int n = 07516(八进制)
package cn.tedu; public class HexDemo { public static void main(String[] args) { System.out.println(027545); } } pint:12133
十六进制
权:4096 256 16 1
规则:逢十六进一
基数:16
数字:0 1 2 3 4 5 6 7 8 9 a b d e f
转十进制:把各按权位不为0的数相加
直面量前缀:0x int n = 0x292d8f(十六进制)
package cn.tedu; public class HexDemo { public static void main(String[] args) { System.out.println(0x292d8f); } } pint:2698639
用途:因为二进制书写太麻烦,所以常用16进制来缩写2进制 如何缩写:将二进制从低位开始每4位进制缩为1个16进制(每4位1缩),高位不够4位在前面补0
补码
计算机处理有符号数(负数)的一种编码方式
计算的时候如果超出四位则高位自动舍弃,保持四位不变
将4位2进制分一半作为负数使用
看正负值时先补全32位,再看高位为1则为负,0则正数(最高位1负,最高位0正)
计算负值:用-1减去0位置对应的权
互补对称现象:-n=n~1+1,-n=n~1-1
位运算
~
0变1,1变0
&
见0则0,双1则1
|
见1则1
>>右移
将2进制数整体向右移,低位自动溢出舍弃,高位补0;右移n位,相当于除以2的n次方
<<左移
将2进制数整体向左移,高位自动溢出舍弃,低位补0;左移n位,相当于乘以2的n次方
一阶段面试题
1、接口与抽象类的区别: 抽象类可以放构造方法; 接口没有构造方法。 抽象类可以放普通成员变量; 接口不可以。 抽象类可以放普通方法也放抽象方法;JDK1.8以前接口中只能放抽象方法。现在其实可以加静态的方法。 抽象类中的成员(变量或方法) 可以加访问修饰符; 接口中修饰符默认都是public。 接口不可以实现接口,但是可以继承接口。 一个类只可以继承一个类 ,但是可以实现多个接口。
递归算法
案例1
class Recursion { public static void main(String[] args) { System.out.println(sum(1,3)); } public static int sum(int start,int end) { if (start == end) { return end; } return start + sum(start+1,end); } }
案例2
class RecursionFactorial { public static void main(String[] args) { System.out.println(factorial(5)); } public static int factorial(int n) { if (n == 1) { return 1; } return n * factorial(n-1); } }
案例3
class C { public static void main(String[] args) { // System.out.println(haha("A")); // System.out.println(haha("ABCDE")); System.out.println(haha("ABCD")); } static String haha(String s) { // "ABC" -------> C + haha("AB") // "ABC" -------> C + B + haha("A") if (s.length() == 1) { return s; } return s.substring(s.length()-1) + haha(s.substring(0,s.length()-1)); } }
实战案例
class D { public static void main(String[] args) { delete(new File("C:\\Users\\southtianmen\\Desktop\\haha")); } static void delete(File dir) { File[] files = dir.listFiles(); for (File file1: files) { if (file1.isFile()) { file1.delete(); } else { delete(file1); } } dir.delete(); } } //递归删除目录
冒泡算法
equals和==的区别
java是值传递还是引用传递
Java中无论是基本类型还是引用类型都是值传递
对于基本数据类型而言,传递的是具体值的副本
对于引用类型而言,传递的是地址值的副本
接口有什么作用 对项目的帮助
定义接口其实是在定义一套规则
1、大学期间做的最好最满意的项目? 2、介绍项目? 3、开发的时间(项目)? 4、基本每天花多长时间在开发上? 5、项目是你一个人做的吗? 6、在项目中遇到什么印象深刻的困难? 7、印象深刻的卡点?(单点登录)通过什么方式解决的? 8、JVM的垃圾回收算法(新生代,老年代)? 9、怎么检测死锁? 10、多态? 11、接口和抽象类的区别? 12、设计模式有哪六大原则? 13、301、302的区别? 14、线程安全和线程不安全? 15、如何保持redis和数据库的一致性? 16、目前面试过其他家吗? 17、你还有其他问题吗?
设计小窍门
能用父类,绝不用子类
如果用子类意味着把类型写死了,拓展性不强
JavaEE
File
/** * java.io.File * File的每一个实例用于表硬盘上的一个文件目录,实际是表示的是一个抽象路径 * 1、可以访问文件或目录的属性(名字、大写、创建时间) * 2、操作文件或目录(删除、创建) * 3、访问一个目录的所有子项 * 但是File不能访问文件数据 * 在当前目录下创建100个文件,名字为test.txt -- test100.txt * * create 创建 * * file 文件 * * exists 存在 * * 使用 File 创建一个文件 */ package file; import java.io.File; import java.io.IOException; public class Test1 { public static void main(String[] args) throws IOException { for (int i = 1; i <= 100; i++) { File file = new File("./txt/test"+i+".txt"); if (file.exists()){ System.out.println("该文件已存在"); }else { file.createNewFile(); System.out.println("文件 " +file.getName()+" 已创建成功"); } } } }
* 使用 File 创建一个文件 * create 创建 * file 文件 * exists 存在
路径
项目本地路径
“test.txt” 默认根目录
网络路径
学习方法
teacherJiang
1、初期讲究的是临摹,不是创新 2、先看一次别人的代码,然后关掉演示,再自己写。
API文档