Java基础篇
java基础
Java的特性优势
- 简单性
- 面向对象
- 可移植性
- 高性能
- 分布式
- 动态性 【反射机制】
- 多线程
- 安全性 【异常机制】
- 健壮性
java三大版本
- write once 、run anywhere
- javaSE:标准版 【桌面程序、控制台开发....】
- javaME:嵌入式开发【手机,小家电....】 用的人很少了
- javaEE:E企业级开发【web端,服务器开发.....】
JDK JRE JVM
JVM ---》 JRE ---》 JVM
java程序运行机制
-
编译型: 把程序全部翻译成计算机可以执行的语言 compile 编译器
-
解释性: 边执行边解释
-
程序运行机制:
-
源程序(.java)---》 java编译器---》字节码(.class) ---》
类装载器---》字节码检验器---》解释器----》操作系统平台
-
标识符
- java标识符大小写敏感;
- java标识符只能以字母 $ _ 开头
数据类型
-
强类型语言
要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用
-
弱类型语言
浮点数
float f = 0.1f;
double d = 1/10;
System.out.println(f==d);//fasle
float d1 = 23232323231f;
float d2 = d1+1;
System.out.println(d1==d2);//true
- float 有限 离散 舍入误差 大约 接近但不等于
- double
- 最好完全避免使用浮点数进行比较
- BigDecimal 类 数学用具类 大数据类 【用这个】
字符
char c1 ='a';
char c2 = '中';
System.out.println(c1);// a
System.out.println((int)c1);// 97 强制类型转换
//所有的字符本质还是数字
//编码 Unicode 有表:(97 = a 65 =A) 2字节 0 - 65526
// U0000 UFFFF
char c3 = '\u0061'
System.out.println(c3);// a
//转义字符
// \t 制表符
// \n 换行符
System.out.println("Hello\tworld");
System.out.println("Hello\nworld");
//看一个e.g.
String sa = new String("hello world");
String sb = new String("hello world");
System.out.println(sa==sb);//false
String sc = "hello world";
String sd = "hello world";
System.out.println(sc==sd);//true
类型转换
-
由于Java是强类型语言,所以要进行有些运算的时候,需要用到类型转换
低 ---------------------到----------------------高
byte , short , char ---> int ---->long ---->float ---->double
-
强制类型转换 高 赋值 到 低 [会有内存溢出 和 精度 问题]
-
自定类型转换 低 赋值 到 高
int i = 128;
byte b = (int) i;//内存溢出 -128
double d = i;
//操作比较大的输的时候。注意溢出问题
int money = 10_0000_0000;//JDK7 新特性 数字之间可以用下划线分割
int years = 20;
int total = money * years; // -147483648,计算的时候溢出了
long total2 = money * years;//默认是int 转换之前还是int 就有问题了
long total3 = money * ((long)years);//先把一个数转化为long √
变量
变量作用域
- 类变量 必须有static
- 实例变量
- 局部变量
常量
- 用final来定义 一般名大写
运算符
- 算术运算符 : + - * / % ++ --
int e = 3;
int f = e++; //执行这行代码,先给f赋值,在自增
System.out.println(e);//4
int g = ++e;//执行这行代码,先自增,后给g赋值
int h = e++;//先赋值,在自增
System.out.println(e);//6
System.out.println(f);//3
System.out.println(g);//5
System.out.println(h);//5
// 字符串连接符 +
int a = 10;
int b = 20;
System.out.println(""+a+b);//1020
System.out.println(a+b+"");//30
- 赋值运算符 : =
- 关系运算符 : > < >= <= == != instanceof
- 逻辑运算符 : && || ! 与或非
[注:] &&: 有0 返回 || : 有 1 返回 --------- 短路机制
- 位运算符 : & | ^ ~ >> << >>>(了解)
System.out.println(2<<4);//<<左移乘2 >>右移除2
- 条件运算符 : ? :
- 扩展赋值运算符: += -= *= /=
JavaDos
/**
* @author shuang 作者
* @version 1.0 版本号
* @since 1.8 指明需要最早使用的JDK版本
* @param in 参数名
* @return 返回值情况
* @throws 异常抛出情况
*/
public String test(String in){
return in;
}
>javadoc -encoding utf-8 -charset utf-8 Doc.java
1、在cmd中运行上面命令会生成在线文档 点击index.html 可查看
2、也可以用IDEA生成javaDoc文档
Java流程控制
Scanner对象
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("第一次输入数据:");//hei baby
// nextLine输出回车之前的数据 以回车分割
String str = scanner.nextLine();
System.out.println(str);//hei baby
System.out.println("第二次输入数据:");//hello world
// next输出空格之前的数据 以空格分割
str = scanner.next();
System.out.println(str);//hello
scanner.close();
}
示例:
public static void main(String[] args) {
//输入多个数字 求总和 平均值 每输入一个数字回车,通过非法数字来结束输入输出执行结果
Scanner scanner = new Scanner(System.in);
double sum = 0;
int m = 0;
System.out.println("请输出数据:");
while (scanner.hasNextDouble()){
double x = scanner.nextDouble();
m++;
sum+=x;
System.out.println("输入了第【"+m+"】个数据 当前总和为:"+sum);
}
System.out.println(m+"个数总和:"+sum);
System.out.println(m+"个数平均值:"+(sum/m));
scanner.close();
}
结果:
请输出数据:
36
输入了第【1】个数据 当前总和为:36.0
42
输入了第【2】个数据 当前总和为:78.0
7.6
输入了第【3】个数据 当前总和为:85.6
a
3个数总和:85.6
3个数平均值:28.53333333333333
顺序结构
- def:语句与语句之间是按从上到下的顺序进行的,它是由若干依次执行的处理步骤组成的,它是任何一个算法都离不开的一种基本算法结构。
选择结构
- if单选择结构
if(布尔表达式){
// 布尔表达式为true
}
- if双选择结构
if(布尔表达式){
// 布尔表达式为true
}else{
// 布尔表达式为false
}
- if多选择结构
if(布尔表达式1){
// 布尔表达式1为true
}else if(布尔表达式2){
// 布尔表达式2为true
}else if(布尔表达式3){
// 布尔表达式3为true
}else if(布尔表达式4){
// 布尔表达式4为true
}else{
// 以上布尔表达式都不为true 执行代码
}
示例:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入成绩:");
int score = scanner.nextInt();
if (score == 100){
System.out.println("恭喜~~满分~~");
}else if (score >= 90 && score < 100){
System.out.println("A级");
}else if (score >= 80 && score < 90){
System.out.println("B级");
}else if (score >= 70 && score < 80){
System.out.println("C级");
}else if (score >= 60 && score < 70){
System.out.println("D级");
}else if (score >= 0 && score < 60){
System.out.println("不及格");
}else {
System.out.println("成绩不合法!!!");
}
scanner.close();
}
结果:
请输入成绩:
100
恭喜~~满分~~
- switch多选择结构
switch(expression){
case value:
//语句
break;//可选
case value:
//语句
break;//可选
case value:
//语句
break;//可选
default://可选
//语句
}
//注: case标签 必须为 字符串常量或字面量
//了解一下反编译 java ---- 字节码 ---- 反编译(IDEA) --- java
反编译(IDEA)示例
查看工程结构 projectStructure --- project ---project compiler output
可以找到.class文件 --- 右键任意文件 --- show in explorer(打开目录) ---
把.class文件拷贝到此目录下 --- IDEA把字节码反编译为java
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package struct;
public class Demo03 {
public Demo03() {
}
public static void main(String[] args) {
char grade = 108;
switch(grade) {
case 65:
System.out.println("优秀");
break;
case 66:
System.out.println("良好");
break;
case 67:
System.out.println("及格");
break;
case 68:
System.out.println("很差");
break;
case 69:
System.out.println("挂科");
break;
default:
System.out.println("未知等级!");
}
}
}
循环结构
- while循环
while(布尔表达式){
//布尔表达式true
}
//注:大多数情况会让循环停止下来,需要让表达式失效方式来结束循环;
示例:
public static void main(String[] args) {
// 1-100 求和
int i = 0;
int sum = 0;
while (i<100){
i++;
sum = sum + i;
}
System.out.println(sum);//5050
}
- do while 循环
do whlile 和 while 相似,不同的是 do while 循环至少执行一次
do{
//代码语句
}while(布尔表达式)
- for循环
- for循环语句是支持迭代的一种结构,是最有效,最灵活的循环语句
for(初始化;布尔表达式;更新){
//代码语句
}
示例1:
public static void main(String[] args) {
// 0-100 奇数偶数和
int oddSum = 0;
int evenSum = 0;
for (int i = 0; i < 100; i++) {
if(i% 2 == 0){
evenSum+=i;
}else {
oddSum+=i;
}
}
System.out.println("偶数和:"+evenSum);
System.out.println("奇数和:"+oddSum);
}
结果1:
偶数和:2450
奇数和:2500
示例2:
public static void main(String[] args) {
//输出 1- 100 之间能被5整除的数,并且每行输出3个
for (int i = 1; i <= 100; i++) {
if(i%5 == 0){
System.out.print(i + "\t");
}
if (i%15 == 0){
System.out.println();
}
}
}
结果2:
5 10 15
20 25 30
35 40 45
50 55 60
65 70 75
80 85 90
95 100
示例3:
public static void main(String[] args) {
//打印九九乘法表
for (int i = 1; i < 10; i++) {
for (int j = 1; j < i+1; j++) {
System.out.print(j+"*"+i+"="+(i*j)+"\t");
}
System.out.println();
}
}
结果3:
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
- 增强for循环
- jdk5引入主要用于数组或集合的增强型for循环
for(声明语句 : 表达式){
//代码句子
}
-
break 与 continue
break:强制退出循环 continue : 终止某一次循环
练习
public static void main(String[] args) {
//打印三角形
for (int i = 1; i <= 5; i++) {
for (int j = 5; j >= i; j--) {
System.out.print(" ");
}
for (int j = 1; j <= i; j++) {
System.out.print("*");
}
for (int j = 1; j < i; j++) {
System.out.print("*");
}
System.out.println();
}
}
结果
*
***
*****
*******
*********
Java方法详解
e.g :System.out.println() 类System中out对象的println()方法
- 一个方法只能完成一个功能 (原子性),这样利于我们后期的扩展。
方法的重载
- 重载就是在一个类中,有相同的函数名称,但形参不同的函数。
- 方法的重载的规则
- 方法名称必须相同
- 参数列表必须不同[个数不同、或类型不同,参数排列顺序不同等]
- 方法的返回值可相同可不同
- 仅仅返回值不同不足以成为方法的重载
- 实现理论
- 方法名称相同时,编译器会根据调用方法的参数个数,参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错
命令行传参(了解)
-
找到class的路径直接cmd 运行javac xxx.class (没问题) ---> java xxx 汇报错error:找不到或无法加载主类。
-
必须回到src文件夹通过包名去执行,并且可以给定参数
可变参数
- 从jdk1.5开始,java支持传递同类型的可变参数给一个方法
- 在方法声明中,在指定参数类型后面一个省略号(...)
- 一个方法中只能指定一个可变参数,它必须时方法的最后一个参数,任何普通的参数必须在它之前声明
示例:
public class Demo04 {
public static void main(String[] args) {
printMax(33,5.6,4.77,53.7);
}
public static void printMax(double... numbers){
if (numbers.length == 0){
System.out.println("数组为空");
return;
}
double result =numbers[0];
for (int i = 1; i < numbers.length; i++) {
if (numbers[i] > result){
result = numbers[i];
}
}
System.out.println("最大的数是:"+result);
}
}
结果:
最大的数是:53.7
递归
- 递归就是自己调用自己
- 递归结构包含两个部分
- 递归头:什么时候不调用自身方法,如果没有头,将陷入死循环
- 递归体:什么时候需要调用自身的方法
示例
public class Demo06 {
public static void main(String[] args) {
System.out.println(fun(4));
}
//递归求阶乘
public static int fun(int n){
if (n == 1){
return 1;
}else {
return n*fun(n-1);
}
}
}
结果:
24
练习
写一个计算器 下面这个例子需要优化
public class Calculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while(true){
System.out.println("请输入表达式");
double x = Double.parseDouble(scanner.nextLine());
String ch = scanner.nextLine();
double y = Double.parseDouble(scanner.nextLine());
double result =0;
switch (ch){
case "*":
result =cheng(x,y);
break;
case "/":
result =chu(x,y);
break;
case "+":
result=add(x,y);
break;
case "-":
result= sub(x,y);
break;
default:
System.out.println("输入运算符号错误!");
break;
}
System.out.println(result);
}
}
public static double add(double x,double y){
return x+y;
}
public static double sub(double x,double y){
return x-y;
}
public static double cheng(double x,double y){
return x*y;
}
public static double chu(double x,double y){
return x/y;
}
}
结果:
请输入表达式
3
+
8.6
11.6
请输入表达式
4
*
6
24.0
请输入表达式
6
/
3
2.0
请输入表达式
坑:next系列函数与nextLine连用有问题
- next() nextInt() nextDouble() ... next系列函数 读缓存时会把回车终止符留在缓存区,下次遇到nextLine会遇到堵孔情况
数组
- 数组是相同类型数据的有序集合
- 数组描述的是相同类型的若干个数据,按照一定的先后顺序排列组合而成(看你放数据的顺序哦)
- 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们
- 数组的声明与创建
//方式一
int[] numbers;//声明 一个数组
numbers = new int[10]// 创建一个数组
numbers[0] = 10;//赋值
//方式二
int[] nums = {10,10,20,10};
- 内存分析
-
数组的四个基本特点
- 长度是确定的,数组一旦被创建,它的大小就是不可以改变的
- 元素必须是相同类型,不允许出现混合类型
- 数组中的元素可以是让任意类型,包括基本类型(int)和引用类型(Man)
- 数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中 (只要是new出来的都在堆中)
-
数组边界
ArrayIndexOutOfBoundsException:数组下标越界!
- 数组使用
示例
public class ArrayDemo04 {
public static void main(String[] args) {
int[] array = {1,2,3,4,55};
for (int i : reverseV2(array)) {
System.out.println(i);
}
}
public static int[] reverse(int[] array){
int[] result = new int[array.length];
for (int i = 0; i < array.length; i++) {
result[array.length-1-i] = array[i];
}
return result;
}
public static int[] reverseV2(int[] array){
int[] result = new int[array.length];
for (int i = 0, j=array.length-1; i < array.length; i++,j--) {
result[j]=array[i];
}
return result;
}
}
结果:
55
4
3
2
1
多维数组
public static void main(String[] args) {
int[][] array = {{1,2},{2,4},{5,6}};
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.println(array[i][j]);
}
}
}
Array
- 数组的用具类java.util.Arrays
- Arrays中的方法都是static静态的直接类点方法调用
- 常用的功能
- 给数组赋值:fill方法
- 对数组排序: sort方法
- 比较数据:用equals方法比较数组中元素值是否相等
- 查找数组元素:binarySearch方法能对排序好的数组进行二分查找法操作
示例:
public static void main(String[] args) {
int[] a = {1,2,5464,353,46,55,415,766,6,64};
System.out.println(a);//哈希值
System.out.println(Arrays.toString(a));
Arrays.sort(a);//排序 小到大
System.out.println(Arrays.toString(a));
Arrays.fill(a,0);//0去覆盖
System.out.println(Arrays.toString(a));
Arrays.fill(a,2,4,8);//对其中的一些值赋值
System.out.println(Arrays.toString(a));
}
结果:
[I@1b6d3586
[1, 2, 5464, 353, 46, 55, 415, 766, 6, 64]
[1, 2, 6, 46, 55, 64, 353, 415, 766, 5464]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 8, 8, 0, 0, 0, 0, 0, 0]
冒泡排序
- 冒泡排序无疑是最为出名的排序算法之一,总共有八大排序
- 冒泡的代码,两层循环,外层冒泡轮数,里层依次比较
- 我们看到嵌套循环,应该立马就可以得出这个算法的时间复杂度是O(n2)
示例
import java.util.Arrays;
public class ArrayDemo07 {
public static void main(String[] args) {
int[] a = {1,45,43,54,2,53,58,64};
System.out.println(Arrays.toString(sort(a)));
}
//冒泡排序
//1、比较数组中,两个相邻的元素,如果第一个比第二个大,就交换位置
//2、每一次比较,就会产生一个最大或者最小的数
//3、下一轮可以 少一轮比较
public static int[] sort(int[] array){
//优化:设置一个标记位 如果已经有序 不用再比较了
boolean flag = false;
int temp = 0;
for (int i = 0; i < array.length-1; i++) {
for (int j = 0; j < array.length-1-i; j++) {
if (array[j+1]>array[j]){
temp =array[j];
array[j]=array[j+1];
array[j+1] = temp;
flag =true;
}
if (!flag){
break;
}
}
}
return array;
}
}
结果:
[64, 58, 54, 53, 45, 43, 2, 1]
稀疏数组
- 需求:编写五子棋游戏中,有存盘退出和续上盘的功能。
- 分析问题:下棋子的地方在二维数组中置1,没有子点的置0,因为该二维数组的狠多值是默认0,因此记录了很多没有意义的数据。
- 解决:稀疏数组
稀疏数组介绍
- 当一个数组中大部分元素为0,或者为同一值的数组时,可以使用稀疏数组来保存该数据。
- 稀疏数组的处理方式;
- 记录数组一共有几行几列,有多少个不同值
- 把具有不同值的元素和行列及值记录在一个小规模的数组中,从而缩小程序的规模
示例:
package array;
public class ArrayDemo08 {
public static void main(String[] args) {
//创建一个二维数组 11*11 0 没子 1黑棋 2 白棋
int[][] array1 = new int[11][11];
array1[1][2] = 1;
array1[2][3] = 2;
System.out.println("输出原始数组");
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1[i].length; j++) {
System.out.print(array1[i][j] + "\t");
}
System.out.println();
}
//转化为稀疏数组保存
//获取有效值的个数
int sum = 0;
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1[i].length; j++) {
if (array1[i][j] != 0) {
sum++;
}
}
}
System.out.println("有效值的个数:"+sum);
//创建一个稀疏数组
int[][] array2 = new int[sum+1][3];
array2[0][0] = 11;
array2[0][1] = 11;
array2[0][2] = sum;
//遍历二维数组 将非零的值 存入稀疏数组中
int count = 0;
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1[i].length; j++) {
if (array1[i][j] != 0){
count++;
array2[count][0] = i;
array2[count][1] = j;
array2[count][2] = array1[i][j];
}
}
}
System.out.println("输出稀疏数组:");
for (int i = 0; i < array2.length; i++) {
for (int j = 0; j < array2[i].length; j++) {
System.out.print(array2[i][j]+"\t");
}
System.out.println();
}
System.out.println("稀疏数组还原:");
int[][] array3 = new int[array2[0][0]][array2[0][1]];
for (int i = 1; i < array2.length; i++) {
array3[array2[i][0]][array2[i][1]] = array2[i][2];
}
//打印还原数组
for (int i = 0; i < array3.length; i++) {
for (int j = 0; j < array3[i].length; j++) {
System.out.print(array3[i][j]+"\t");
}
System.out.println();
}
}
}
结果:
输出原始数组
0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0
0 0 0 2 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
有效值的个数:2
输出稀疏数组:
11 11 2
1 2 1
2 3 2
稀疏数组还原:
0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0
0 0 0 2 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
Process finished with exit code 0
面向对象编程OOP
什么是面向对象
-
面向对象编程(Object-Oriented Programming OOP)
-
面向对象编程的本质就是:以类的方式组织代码,以对象的形式组织(封装)数据。
-
抽象
-
三大特性:封装、继承、多态
-
值传递和引用传递
示例:引用传递
package oop;
public class Demo05 {
//引用传递:对象,本身还是值传递
//对象 内存!
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);
Demo05.change(person);
System.out.println(person.name);
}
public static void change(Person person){
person.name = "Shuang";
}
}
class Person{
String name;
}
结果:
null
Shuang
示例:值传递
package oop;
public class Demo04 {
//值传递
public static void main(String[] args) {
int a = 1;
System.out.println(a);
Demo04.change(a);
System.out.println(a);
}
public static void change(int a){
a=10;
}
}
结果:
1
1
类与对象的关系
- 对象---是具体的事物,类---是抽象的 是对对象的抽象,类--是对象的模板
创建与初始化对象
-
使用new关键字创建对象
-
使用new关键字创建对象的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化 及 对类中构造器的调用
-
构造方法:
- 方法名必须跟类名相同
- 没有返回值
-
构造器作用
- new 本质在调用构造方法
- 初始化对象的值
注意点:
- 定义有参构造器,如果想使用无参构造器,必须显示的定义一个无参构造器
内存分析
package oop;
import oop.demo03.Pet;
public class Application {
public static void main(String[] args) {
Pet dog = new Pet();
dog.name = "旺财";
dog.age = 3;
dog.shout();
System.out.println(dog.name);
System.out.println(dog.age);
Pet cat = new Pet();
}
}
package oop.demo03;
public class Pet {
public String name;
public int age;
public void shout(){
System.out.println("叫了一声");
}
}
注意:左面是栈,右边是堆,堆里面有个特殊区叫方法区
简单小结类与对象
-
类与对象
- 类是一个模板:抽象 , 对象是一个具体的实例
-
方法
- 定义 调用
-
对象的应用
-
引用类型 + 基本类型(8个)
对象是通过引用来操作的:栈----》堆 (地址)
-
-
属性:字段Field 成员变量
-
默认初始化: 数字 --- 0 0.0
char --- u0000
boolean --- false
引用 --- null
-
修饰符: 属性类型 属性名 = 属性值!
-
-
对象的创建和使用
- 必须使用new 关键字创造对象,构造器
-
类:
- 静态的属性 --- 属性
- 动态的行为 --- 方法
封装
-
该露的露,该藏的藏
-
就是设计程序“高内聚,低耦合”
高内聚:就是类的内部数据操作细节自己完成,不允许外部干涉
低耦合:仅暴露少量的方法给外部使用
-
-
属性私有:get/set
-
封装好处
- 提高代码的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口 get/set [有时set 里面对数据进行不合法判断]
- 增加系统可维护性
继承
- Java中类只有单继承,没有多继承!
- extends关键字
- java中所有的类都继承Object类
- 私有的 不可以继承
super this 注意点
-
super调用父类的构造方法,必须在子类方法的第一个
-
super 必须只能出现在子类的方法或者构造方法中!
-
super 和 this 不能同时调用构造方法!
-
VS this
- this:本身调用者这个对象
- super:代表父类对象的应用
前提:
this:没有继承也可以使用
super: 只能在继承套件才可以使用
构造方法:
this() : 本类的构造
super():父类的构造
重写
- 需要有继承关系,子类重写父类的方法
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大 public > protected > default > private
- 抛出的异常:范围,可以缩小,但不能扩大;e.g.原来是 Exception(大)可以变为 ---》 ClassNotFoundException
- 重写:子类和父类必须要一致,方法体不同
静态方法
- 子类父类静态方法 名与参数相同 不构成重载 [IDEA中重写方法旁 有个蓝色的小o]
示例:
package oop;
import oop.demo05.A;
import oop.demo05.B;
public class Application {
//静态方法和非静态方法区别很大!
//静态方法:
// 方法的调用只跟左边,定义的数据类型有关
//非静态方法:
// 重写
public static void main(String[] args) {
A a = new A();
a.test();
a.test2();
//父类的引用指向了子类
B b = new A();//子类重写了父类的方法
b.test();
b.test2();
}
}
package oop.demo05;
public class A extends B{
@Override
public void test() {
System.out.println("A=>test()");
}
public static void test2() {
System.out.println("A=> static test()");
}
}
package oop.demo05;
public class B {
public void test(){
System.out.println("B=>test()");
}
public static void test2() {
System.out.println("B=> static test()");
}
}
结果:
A=>test()
A=> static test()
A=>test()
B=> static test()
多态
-
动态编译:类型,可扩展性
-
即同一方法可以根据发送对象的不同而采用多种不同的行为方式
-
一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多[父类,有关系的类]
-
注意事项:
-
多态是方法的多态,属性没有多态
-
父类和子类,有联系,类型转换异常 ClassCastException 类型转换异常
-
存在条件:继承关系,子类重写父类方法,父类引用指向子类对象
e.g. Person s1 = new Student();
-
static final 修饰 方法不能重写 [static方法属于类 它不属于实例],private方法是私有的也不能重写
-
instanceof (类型转换) 引用类型
-
示例:
package oop.demo06;
public class Person {
public void run(){
System.out.println("run");
}
}
package oop.demo06;
public class Student extends Person{
@Override
public void run() {
System.out.println("student run");
}
public void eat(){
System.out.println("Student eat");
}
}
package oop;
import oop.demo05.A;
import oop.demo05.B;
import oop.demo06.Person;
import oop.demo06.Student;
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
// new Person();
// new Student();
//可是指向的引用类型就不确定了
//子类能调用的方法都是自己的或者继承父类的
//父类型 可以指向子类,但不能调用的子类独有的方法
Student s1 = new Student();
Person s2 = new Student();//父类的引用指向子类
Object s3 = new Student();
s1.run();
s2.run(); // 子类重写了父类的run方法
//对象能执行哪些方法,主要看对象左面的类型,和右面关系不大
// s2.eat()//err 父类没有eat方法 eat是子类的
}
}
结果:
student run
student run
instanceof
示例:
package oop;
import oop.demo05.A;
import oop.demo05.B;
import oop.demo06.Person;
import oop.demo06.Student;
import oop.demo06.Teacher;
public class Application {
public static void main(String[] args) {
// Object 》 Person 》 Student
// Object 》 Person 》 Teacher
// Object 》String
//System.out.println(X instanceof Y) //能不能编译通过
Object object = new Student();
System.out.println(object instanceof Student);//true
System.out.println(object instanceof Person);//true
System.out.println(object instanceof Object);//true
System.out.println(object instanceof Teacher);//false
System.out.println(object instanceof String);//false
System.out.println("----------------------");
Person person = new Student();
System.out.println(person instanceof Student);//true
System.out.println(person instanceof Person);//true
System.out.println(person instanceof Object);//true
System.out.println(person instanceof Teacher);//false
// System.out.println(person instanceof String); 编译报错
System.out.println("----------------------");
Student student = new Student();
System.out.println(student instanceof Student);//true
System.out.println(student instanceof Person);//true
System.out.println(student instanceof Object);//true
// System.out.println(student instanceof Teacher);编译报错
// System.out.println(student instanceof String);编译报错
}
}
结果:
true
true
true
false
false
----------------------
true
true
true
false
----------------------
true
true
true
static
- static 不能修饰类
- static静态代码块和包
示例:
package oop.demo07;
public class Person {
{
System.out.println("匿名代码块");//在构造器之前调用 赋初始值
}
static {
System.out.println("静态代码块");//只执行一次
}
public Person(){
System.out.println("构造方法");
}
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();
}
}
结果:
静态代码块
匿名代码块
构造方法
匿名代码块
构造方法
示例:
package oop.demo07;
import static java.lang.Math.PI;
import static java.lang.Math.random; // 用静态包
public class Test {
public static void main(String[] args) {
System.out.println(random()); // 直接写Math里面的方法和常量即可 不用在带上 Math
System.out.println(PI);
}
}
final
- final 修饰类---不能在更改与继承、断子绝孙 hhh
抽象类
package oop.demo08;
public abstract class Action {
//约束 有人帮我们实现
//抽象方法 只有方法的名字 没有实现
public abstract void doSomething();
//1、不能new这个抽象类,只能靠子类去实现它:约束!
//2、抽象类中可以写抽象方法
//3、抽象方法必须在抽象类中
//4、抽象的抽象
//思考? 1、 抽象类new不出来 它存在构造器吗?
// 2、抽象类存在的意义 :抽象出来公共的东西--提高开发效率--可扩展性高
}
接口
- 普通类:只有具体的实现
- 抽象类:具体实现和规范(抽象方法)都有!
- 接口:只有规范
- 接口的关键字是interface
- 接口的本质是契约
接口作用
- 约束
- 定义一些方法,让不同的人实现
- 接口中的所有定义的方法都是public abstract
- 接口中定义常量都是 public static final
- 接口不能被实例化,接口中没有构造方法
- implements可以实现多个接口
- 必须要重写接口中的方法
内部类
- 内部类就是在一个类的内部在定义一个类,比如A类中定义一个B类,那么B类相对A类来说就成为内部类,而A类相对于B类来说就是外部类了。
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
- lambda表达式细看内部类
demo1看一下
package oop.demo10;
public class Outer {
private int id = 10;
public void out(){
System.out.println("这是外部类的方法");
}
private void print(){
System.out.println("外部类私有的方法");
}
private void test(){
class One{
}
}
public class Inner{
public void in(){
System.out.println("这是内部类中的方法");
}
//获得外部类的私有属性和私有方法
public void getId(){
System.out.println(id);
print();
}
}
}
package oop;
import oop.demo10.Outer;
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
//通过外部类来实例内部类
Outer.Inner inner = outer.new Inner();
inner.getId();;
}
}
demo2看一下
package oop.demo10;
public class Test {
public static void main(String[] args) {
//没有名字初始化类 不用将示实例保存到变量中
new Apple().eat();
new UserService(){
@Override
public void hello() {
System.out.println("哈哈哈哈");
}
};
}
}
class Apple{
public void eat(){
System.out.println("123");
}
}
interface UserService{
void hello();
}
异常机制
什么是异常?
-
Exception
-
异常指程序运行中出现的不期而至的各种状况:e.g. 文件找不到,网络连接失败,非法参数等
-
异常发生在程序运行期间,它影响了正常的程序执行流程
简单分类
三种类型异常
- 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序无法预见的。例如要打开一个不存在的文件,一个异常就发生了,这些异常在编译时不能被简单地忽略。
- 运行时异常:运行时异常是可能被程序员避免得异常。与检查性异常相反,运行时异常可以在编译时别忽略。
- 错误ERROR:错误不是异常,而是脱离程序员控制的问题,错误在代码中通常被忽略。例如当栈溢出时,一个错误就发生了,它们在编译也检查不到的
异常体系结构
- java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类
- 在JavaAPI中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception
Throwable ---- ERROE ---- VirtulMachineError ...
---- AWTError[GUI错误] ...
---- Exception ---- IOException ...
---- RuntimeException ...
Error
- Error类对象由Java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关
- Java虚拟机运行错误(VirtulMachineError),当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError。这些异常发生时,java虚拟机一般会选择线程终止
- 还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、链接错误(LinkageError)。这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数时是程序运行时不允许出现的状况
Exception
- 在Exception分支中有一个重要的子类RuntimeException(运行时异常)
- ArrayIndexOutOfBoundsException 数组下标越界
- NullPointerException 空指针异常
- ArithmeticException 算术异常
- MissingResourceException 丢失资源
- ClassNotFoundException 找不到类 这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理
- 这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生
- Error和Exception的区别:Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程;Exception通常情况下时可以被程序处理的,并且程序中应该尽可能的去处理这些异常
异常处理机制
- 抛出异常
- 捕获异常
- 异常处理的五个关键字
- try
- catch
- finally
- throw
- throws
package exception;
public class Test {
public static void main(String[] args) {
int a = 1;
int b = 0;
try {
new Test().a();
System.out.println(a/b);
}catch (Error e){//catch 捕获异常异常 !!捕获多个异常 : 小----大 要先捕获小范围异常在到大范围异常
System.out.println("Error");
}catch (Exception e){
System.out.println("Exception");
}catch (Throwable e){
System.out.println("Throwable");
} finally {
System.out.println("Finally");// 无论有无异常 都会执行 一般善后
//一般用来IO 资源 关闭!
}
}
public void a(){
b();
}
public void b(){
a();
}
public void test(int a,int b) throws ArithmeticException{ //方法上抛出异常时throws
if (b==0){ //主动抛出异常 throw throws
throw new ArithmeticException();//一般在方法中使用
}
}
}
自定义异常
- 用户自定义异常,只需要继承Exception即可
- 在程序中使用自定义异常,大体可以分以下几个步骤
- 创建自定义异常
- 在方法中通过throw关键字抛出异常对象
- 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作
- 在出现异常方法的调用者中捕获并处理异常
示例:
package exception;
public class MyException extends Exception{
//传递数字>10
private int detail;
public MyException(int detail) {
this.detail = detail;
}
//toString
@Override
public String toString() {
return "MyException{" +"detail=" + detail + '}';
}
}
package exception;
public class Test3 {
static void test(int a) throws MyException{
System.out.println("传递的参数:"+a);
if (a>10){
throw new MyException(a);
}
System.out.println("OK");
}
public static void main(String[] args) {
try {
test(12);
} catch (MyException e) {
System.out.println("MyException=>"+e);
}
}
}
结果:
传递的参数:12
MyException=>MyException{detail=12}
实际经验的总结
- 处理运行时异常时,采用逻辑去合理规避同时辅助try-catch处理
- 在多重catch块后面,可以加一个catch(Exception大异常)来处理可能会遗漏的异常
- 对于不确定的代码,也可以加上try-catch,处理潜在的异常
- 尽量去处理异常,切忌只是简单的调用printStackTrace()去打印输出
- 具体如何处理异常,要根据不同的业务需求和异常类型去决定
- 尽量添加finally语句块去释放占用的资源 IO Scanner...
IDEA快捷键
- ctrl + D 复制当前行到下一行
- 100.for 回车会自动生成for语句
- alt + insert
- ctrl + H 继承树
- ctrl + alt + t 选中代码 可快速生成try catch