javaSE基础
javaSe 整体大纲
- java基础 (循环,数组)
- OOP
- API
基础
- 编程的本质=数据结构+算法
- 什么是编程:就是让计算机按自己的意图去工作
编程语言的发展史(了解)
- 机器语言:0101
- 汇编语言: 助记符
- 高级语言:java,c,c++,python,basic
为什么是java
流行的语言:
- java,python,c,C++,javascript,go…
- 语言没有好坏之分,只有适不适用?
厨房中的刀,哪把刀更好:砍刀,切菜刀,西瓜刀,水果刀?
- 每个语言都有适用的场景
- 数据分析:python,
- 3D游戏:C++
- 前端页面:javascript
- 应用程序的后台:java
回顾
1.学习方法:编码-》巩固-》检索 3F:focus->feedback->fix
2.课程 se:1.基础 2.oop,3API
3.编程的基础: 数据结构+算法=程序
4.编程语言的发展史
- 机器语言
- 汇编语言
- 高级语言
5.java
- 企业后台
- 安卓
- 大数据
- 桌面
6.java语言的发展史
java语言的发展
高斯林(高司令):嵌入式程序
99年,三个版本:javase,javame,javaee
- LTS
- JDK8
- JDK11
- JDK17
java 语言的特点
- 面向对象
- 简单
- 跨平台
java语言的三个版本
- A:javaSE:标准版本:基础,桌面级应用
- B:javaEE:企业版:服务器端的大网络,分布式
- C:javaME:微型版本:嵌入式设备,小设备
环境安装
JDK
java development kid:java开发包
作用:开发,运行java程序
JRE:java runtime environmentjava 运行环境
作用:运行java程序
JDK包含了JRE
JVM:java virtual machine:java虚拟机
作用:用来运行java程序 不包含类库和命令
JDK中包含了JRE,JRE中包含了JVM
安装JDK
建议:安装 11,8,
安装注意事项
- 傻瓜式安装,按步骤来就行
- 安装路径不要有空格,不要使用中文路径
- 安装后会有两个目录
- bin:包含了java命令:javac(编译),java(运行),javadoc(生成文档)
- lib:包含了java类库
配置:
配置环境变量?
DOS命令
DOS:disk operation system:命令行
命令:
- cd:改变目录
- dir:查看当前目录下的内容
- 盘符:切换到其它盘,例如 D:
- d:切换到D盘
- cd …:切换到上层目录
- cd bin:进入取bin子目录
- dir:显示当前目录中的内容
问题?
java.exe,javac.exe在 d:/java/jdk-11.0.8/bin下,如果想使用java,javac命令,必须先进入到d:/java/jdk-11.0.8/bin下才可以使用,如果希望在任何一个目录下都使用此命令,则需要配置环境变量才可以环境变量中有一个叫path的
path的作用是,当运行一个命令时,先从当前路径找,如找不到,再去path中找如果在path中设置一个值 d:/java/jdk-11.0.8/bin
当我们在 e:盘下,运行 java
- 1.先在 e:/下找java
- 2.如找不到,再到path下找
环境变量
path:路径
classpath:类路径 .d:/java/jdk-11.0.8/lib
window: 图形界面
android:图形
linux:有图形
第一个java程序
public class HelloWorld{
public static void main(String[] args){
System.out.println("这是我的第一个java程序,我好高兴呀,今天晚上给自己加一个鸡腿吧");
}
}
- HelloWorld:是类名,类名必须要与文件名相同 (HelloWorld.java
- System.out.println(“”):代表输出 ""中可以写任何字符串
- 所有的标点符号都是英文半角
- java是区分大小写的
HelloWorld详解
public class Hello{
public static void main(String[] args){
System.out.println();
}
}
//Hello是类名
//public static void main(String[] args):是主函数,程序的入口,如果想直接运行此类,必须有此方法
//System.out.println();输出内容后换行
//System.out.print();输出内容后不换行
//无论是print还是println都只能输出一个内容,内容可以是字符串,数字,布尔等等
//9+9
//"hello"+"hello"+9
java命令
javac:编译
java:运行
javadoc:生成文档
javac语法
javac 文件名.java
javac HelloWorld.java
作用:将.java的源代码编译成.class文件,如果代码有错误,将无法完成编译
java 语法
java 类名
java HelloWorld
注意:千万不要写.class
作用:运行java类,要求此类必须有主函数
javadoc:生成文档
javadoc 类名.java
注释
作用:为了让程序员更容易理解代码的含义,可以使用注释加以说明 注释不会影响代码的运行
注释有三种
//:单行
/* /:块注释
/* */:文档注释
java编程基础
关键字
-
什么是关键字:在java语言有,有特殊含义的一些单词就是关键字
-
关键字的特点:全部都有小写
标识符
- 什么标识符:用来标识某种东西的符号就是标识符
比如:类,方法名,变量名,参数名,
定义标识符的规则
-
标识符中可包含字母,数字,_,$,中文也可以(不建议)
-
不能以数字开头
-
不能是关键字
-
长度无限制,最好做到“见名知义”
变量
变量:就是内存中的一个区域,为了便于使用,需要给变量起个名字
变量用法:
-
变量一定要先定义,再使用
-
定义变量的格式是
数据类型 变量名=初始值
-
变量的值是可以改变的
-
在一个作用域中,变量名是不能重复的
数据类型
java的数据类型分为两大类,分别是
- 基本数据类型
- 引用数据类型
- 类,接口,数组
基本数据类型
-
整数
- byte :1
- short:1
- int :2
- long:2
-
浮点数
- float:45.6f
- double:444.4
-
字符
- char ‘a’
-
布尔
- boolean :true,false
整数:
-
byte:1个字节
-
位(bit)
01:bit,每个一个bit只能存储两个值
一个字节等于8位二进制
10101011
byte = -128~127;
-
-
short:2个字节
-
int:4个字节
-
long:8个字节
关于容量的换算关系
字节 B byte
1KB->1024B
1MB->1024KB
1GB->1024MB
1TB->1024GB
1PB->1024TB
进制的转换
1.10进制-》二进制
除2取余法2.二进制-》十进制
乘权相加法
110101
1+4+16+32=53
3.二进制-》十六进制
1011 1010
B A
100011111
4.十六进制-》二进制
6E-》
字面值(literal)
字面值也叫直接量
1.整数的字面值的类型默认为是int
2.十六进制 0x开头
3.八进制以0开头,例如 int a=011
4.如果想表示一个long值,可以使用 L结尾,例如 long a=12312312399L
浮点型
字节 | 范围 | |
---|---|---|
float | 4 | -3.403E38 ~ 3.403E38 |
double | 8 | -1.798E308 ~ 1.798E308 |
总结
1.浮点数只能表示出一个近似数,而不能表示出一个准确的数
2.浮点数的字值的类型是double,如果想表示一个float,应该使用 F结尾
字符型
用 一对‘’引起的单个字符就是字符,字符可以以数字,英文字母,标点符号,还可以表示任何语言的单字符 例如,中文,法文,俄文,日文
每个字符存储时,都会转换成与之对应的数字
字符与数字之间的对应关系就是一种字符集 UTF-8 GBK,GB2312
char有三种表示方式
1.‘’
2.‘\转义字符’ ,例如 ‘\n’:换行
3.unicode码 ‘\uXXXX’
boolean
boolean叫布尔
只有两个值,分别是true,false
通常来说,可以使用boolean来存储一个状态是否打开音乐
boolean isMusic=false
String类型
String代表字符串,即用双引号引起的多个字符序列
String不是基本数据类型,而是一种引用类型String name=“刘备”
java代码三级跳
1.表达式
类似于语文中的汉字,词组,例如 a+b,c*d
2.语句
类似于语文中的句子。以 号结束 一个语句中会包含多个表达式, int a=5;
int b=a+b;
c=sum+a;
3.代码段
相当于语文的作文,一个代码段中包含多个语句
数据类型的转换
两种转换
1.自动转换:低精度向高精度可以自动转换,安全
2.强制转换:高精度向低精度转换时可以采用强制转换,强转可能会造成精度丢失
数值类的的精度
byte->short->int->long->float->double
char
自动类型转换发生在两种情况
- 赋值
- 运算
强制类型转换
- 高精度向低精度转换时,可使用强转
- 强转的语法是 (数据类型) 例如 long b=6677; int a=(int)b;
Scanner
//有交互的程序
交互的方式主要用两种
1.命令行
2.图形
Scanner叫扫描器,他可以接收用户输入的数据 例如数字,字符串,布尔值等
使用Scanner的步骤
1.导包 import java.util.*
2.创建Scanner对象
Scanner s=new Scanner(System.in)
3.接收数据
int a=s.nextInt()
import java.util.*; //1.导包
public class Circle
{
public static void main(String[] args)
{
//2.创建一个扫描器
Scanner scanner=new Scanner(System.in);
System.out.println("请输入半径");
//3.接收一个半径
double r=scanner.nextDouble();
double area=r*r*3.14;
System.out.println("圆的面积是:"+area);
}
}
运算符
运算符可以有两种分在方式
- 功能
- 算术运算符
- 赋值运算符
- 比较运算符
- 位运算符
- 逻辑运算符
- 条件(三元)运算符
- 操作数的个数
- 一元操作符: ++b,
- 二元操作符: a+b
- 三元操作符 a>b?a:b
算术运算符
++,--
可以放在操作数之前,也可以放在操作数之后
a++操作符有作用
1.对a做一个加操作
2.a++也是一个表达式,即将表达式的结果赋给一个变量
b=a++;
b=++a;
a++;
++a;
赋值运算符
=
例如: a=9+8;
特点:
1.操作符的结合性是从右到左
2.操作符左侧一定是一个变量
比较运算符
==
!=
<
=
<=
instanceof
所有比较运算符的计算结果的类型都是boolean; true,false;
注意,
=是赋值
==是比较
逻辑运算符
与: & ,&&
或: | ||
非: !
异或: ^
与的语法
表达式1 & 表达式2
表达式1 && 表达式2
要求,两个表达式都是布尔表达式
即,两个表达式的结果同时为true时,与后的结果才true;
或: | ||
作用:两个操作数的结果,只要有一个为true,那么或的结果就为true;
非:
取反
!true;=false;
!false:=true;
异或:
作用:两个操作数不同时为true,否则为false;
&,&&的区别?
&,&&都是逻辑与,计算的结果是相同的 但运算的过程是有区别的?
例如
a&&b;
假如,a的结果是false;那么是否需要计算b,才知道整个表达式的结果
区别:
&:无论第一个操作数结果是什么,都会计算所有表达式
&&:如果第一个操作数的结果是false,那么将不会计算第二个表达式
位运算符
操作对象:整数(byte,short,int,long)
作用:将整数转换成二进制后,按位进行运算 常用的操作有,位移,按位与,或,异或
位运算的优点:效率高
:按位右移
<<:按位左移
:无符号右移
&:按位与
|:按位或
^:按位异或
895;
条件运算符
语法
布尔表达式?表达式1:表达式2
int c=a>b?a:b;
Java进阶
流程控制
三种
顺序结构
分支(选择)结构:branch
循环结构:loop
顺序:
程序从上到下,依次执行
分支语句
分支语句分为if,switch
if语句
单分支
语法
if(布尔表达式){
语句块
}
。。
适用场景:
为程序增加一个可能执行的代码,此代码有可能执行,有可能不执行
双分支
if(布尔表达式){
语句块1
}else{
语句块2
}
多分支
语法
if(布尔表达式){
}else if(布尔表达式2){
}else if(布尔表达式3.。。。){
}else{
}
关于if的小结
1.完整的if语句中,包含 if-else if-else
2.if语法中,if是必须存在的, else if可有0到n个,可以有0到1个else
3.如果存在else,else一定放在最后
4.多分支语句中,最多只能执行一个分支,执行此分支后,分支语句结束
if的嵌套
在一个分支语句块中包含另一个分支语句
适用场景:适合解决较为复杂的逻辑问题
例如:
登录
1.成功 用户名,密码,验证码
2.失败
1.验证码?
2.用户名,或密码错误,但少于3次
3.用户名,或密码错误,但大于等于3次 锁定(1个小时)
语法
if(条件){
System.out.println();
i++;
if(){
}
}else if(条件){
if(){
}else{
}
}else{
}
if语句的简化
//如果if语句块中只包含一行代码,那么{}可以省略,(但不建议省略)
if(true)
System.out.println("ok");
else
System.out.println("else");
switch 语句
//语法
switch(表达式){
case 值1:
语句;
break;
case 值2:
语句;
break;
default:
语句3
}
//输入一个成绩 5,4,3,2,1,0
关于break;
在switch语句中,如果case 没有break,那么将会穿透
解决问题
输入月份,判断此月有多少天?
2:28,29
1,3,5,7,8,10,12:31
4,6,9,11:30case:
2,
4,
6,
9,11default:
import java.util.*;
public class Switch2
{
public static void main(String[] args)
{
Scanner s=new Scanner(System.in);
System.out.println("输入月份");
int month=s.nextInt();
switch(month){
case 2:
System.out.println("28或29天");
break;
case 4:
case 6:
case 9:
case 11:
System.out.println("30天");
break;
default:
System.out.println("31天");
}
}
}
使用switch的注意事项
1.switch只能使用等值比较,而且对数据类型有要求(byte,short,int,char,String)
2.注意 case穿透 (break)
3.switch的结果清晰,但没有if应用的广泛
循环
语法很简单,练习是关键
循环语句的三个部分
1.初始化部分(1次)
2.条件部分(多次)
3.循环体部分 (多次)
java中,循环语句的分类
1.while
2.do-while
3.for
while语句
//语法
[初始化语句]
while(表达式){
循环体语句;
}
...
1+2+3+4…+100;
int sum=0;//定义一个变量 用来存储累加的和
int i=1;
sum+=i;(1.2,3,4,5,5.6,7)
盈盈为了考验令狐冲夺冠的决心,要他说一百遍“我能行!”;
1+…100;
死循环
死循环:无法结束的循环被称为死循环
变量的作用域
内层可以使用外层的变量,外层不能使用内层的变量
do-while
//do-while循环
[初使化变量]
do{
循环体
}while(布尔表达式);
特点:至少进入一次循环体
//猜数游戏
Random r=new Random();
int n=r.nextInt(10);//产生一个随机数,(整数)
int i=0;//代表用户猜的那个数值
do{
//猜数
}while(n!=i)
//计算一下,用户用了几次机会
import java.util.*;
public class GuessNumber
{
public static void main(String[] args)
{
Random r=new Random();//创建一个随机数生成器
Scanner s=new Scanner(System.in);//创建一个扫描器,用来接收用户猜的数字
int n=r.nextInt(100)+1;//获得一个随机数
int i=0;//i代表用户每次猜的那个数,如果i==n,说明猜对了
do{
//每次猜数
System.out.println("说出一个数字");
i=s.nextInt();
if(i>n){
System.out.println("高了");
}else if(i<n){
System.out.println("低了");
}
}while(i!=n);
System.out.println("你猜对了,这个数就是:"+n);
}
}
for循环
//语法
for(初始化变量;条件表达式;循环体的最后一个表达式 ){
循环体
}
//特点:非常适用于已知循环次数的程序
int sum=0;
for(int i=0;i<100;i++){
sum+=i;
}
//1.int i=0;
//2( i<100; sum+=i; i++)
break 与 continue
break与continue都是关键字,可以在循环体中使用 (for,while,do-while)
break:结束当前循环(退出循环)
continue:结束当次循环,进入下一次循环判断
嵌套循环
语法结构:
在一个循环体中,包含另外一个循环语句,这种结构就是嵌套循环
循环中的算法
暴力(穷举):数字,字母,特殊字符
顺推:已知条件推结果
逆推:已知结果推条件
数组
数组的定义
1.数组是一种引用数据类型,它可以存储多个相同类型的数据
2.数组的长度一旦定义,不能改变
3.数组中的元素可以通过下标来访问,下标的取值范围是0~长度-1
数组
数组元素的初始化
动态:创建数组后,为元素分别赋值
静态:创建数组的同时,为元素赋值
for each
增强的for循环
作用:遍历集合中的数据
语法:
for(数据类型 变量:数组名){
}
将数组中的元素转成字符串
Arrays.toString(数组)
内存模型
java虚拟机将内容主要分为两个区域,分别是栈和堆
基本数据类型,存在栈中
int i=9;
基本数据类型变量存储的是数据本身
引用类型是存储在堆中的
引用类型有数组,类,接口
int[] a=new int[5];
排序及二维数组
算法
什么是算法:
其实就是解决问题?
如何衡量算法优劣?
时间
空间
时间复杂度:大O表示法
O(1):固定次数,常数
O(logn):二分
O(n):一层循环
O(n方):二层循环
O(n的立方):三层循环
O(2的n次幂):
O(n!):
排序
排序是最常的算法
直接选择排序?
冒泡排序?
未排序,已排序
相邻比较并交换。整个的过程就像冒水泡一样
import java.util.*;
//冒泡排序
public class BubbleSort
{
public static void main(String[] args)
{
int[] nums={12,45,78,5,75,33,23,47};
int temp=0;
//循环n-1次
for(int i=0;i<nums.length-1;i++){
//通过冒泡,每次从未排序堆中选一个最大的,放在已排序堆中
for(int j=0;j<nums.length-1-i;j++){
//交换
if(nums[j]>nums[j+1]){
temp=nums[j];
nums[j]=nums[j+1];
nums[j+1]=temp;
}
}
}
System.out.println(Arrays.toString(nums));
}
}
import java.util.*;
//直接选择排序
public class Sort3
{
public static void main(String[] args)
{
int[] nums={30,78,90,10,4,67};
//将最大的元素与第一个元素进行交换
//1.定义一个变量,用来存储最大元素的下标
for(int i=0;i<nums.length-1;i++){
int max=i;
//1.向未排序堆中找出最大的元素的下标
for(int j=i+1;j<nums.length;j++){
if(nums[max]<nums[j]){
max=j;
}
}
//2.交换
if(max!=i){
int temp=nums[max];
nums[max]=nums[i];
nums[i]=temp;
}
}
System.out.println(Arrays.toString(nums));
}
}
二分法
二分法,也称为折半查找法 前提是,数据一定是已排序的。
时间复杂度为O(logn)
import java.util.*;
public class BinarySearch
{
public static void main(String[] args)
{
int[] nums={1,3,6,7,9,11,23,34,56,67,88,99,100};
Scanner s=new Scanner(System.in);
System.out.println("请输入一个数");
int n=s.nextInt();
int i=0;
int j=nums.length-1;
int m=0;
//1.编写代码,完成查询,如果找到了,输出位置,否则,输出“查无此数”
//2.分别使用O(n) O(logn)来解决?
while(i<=j){
//1.计算出中间位置
m=(i+j)>>1;
if(n==nums[m]){
System.out.println("找到了,位置是:"+m);
break;
}else if(nums[m]>n){
j=m-1;
}else{
i=m+1;
}
}
if(i>j){
System.out.println("查无此数");
}
}
}
二位数组
二维数组
java中其实没有二维数组,所谓的二维数组其实就是一个数组,只不过数组中的元素还是一个数组
int[] nums={3,5,6,7};
int nums=new int3;
二维数组的初使化
静态初使化
int nums={{3,4,5,7},{6,6,6},{8,9,4,3}};
动态初使化
int nums=new int3;
int nums=new int3;
nums[0]=new int[]{3,4,5,6,7,8};
nums[1]=new int[]{333,56};
nums[2]=new int[]{4,4,6,8};
String names={{"刘备","张飞","关羽"},{"曹操"},{"孙权","周瑜"}};
面向对象OOP
面向过程与面向对象
面向对象,强调由谁来做
面向过程,强调怎么做面向过程:把解决问题的步骤列出来,再逐步实现
面向对象:将问题域中的对象找出来,再确定它们之间的关系
面向对象有什么优点
1.更容易理解
2.解决复杂的问题,更有优势
面向对象的基础知识
什么是对象
所有具体的事物都是对象(object)
类
类是一组具有相同属性和行为的一组对象的抽象表示
类和对象的关系:
类是对象的抽象表示
对象是类的一个具体实例
类是抽象的,对象是具体的
class :
定义类的语法
回顾
1.面向过程,面向对象的区别?
2.面向对象的两个重要的概念
对象,类
3.如何定义一个类
class 类名{
属性
方法
}
类中都应该有什么
1.定义一个学生类型
public class student{
int stuno; //定义类的属性
String name;
String sex;
int age;
}
方法
大家用过方法吗?
用过哪呢?
Random r=new Random();
int i=r.nextInt(10);
方法中都包括什么?
方法名:
参数:多个,每个参数都需要有类型
返回值类型:
定义一个方法,判断是否为闰年
定义方法的语法?
返回值类型 方法名(参数列表 ){
方法体
}
int sum(int a){
int s=(1+a)*a/2;
return s;
}
int s=num(100);
s=num(50);
形参和实参的区别?
形参:定义方法时使用的参数,也叫形式参数
实参:调用方法,传递的参数,也叫实际参数
传参的过程就是赋值 即把实参赋给形参
return 用法
1.return语句 可以放在方法体中,代表返回的意思
2.如果一个方法中有return 语句,return 一定作为最后一条语句来存在
3.return 后的表达式的类型一定要与方法的返回值类型一致
4.如果方法返回值类型为void ,那么可以省略return ,或者直接写return
内存结构
略
方法的传参
pass by value:按值传递
pass by ref:按引用传递 (引用类型)
重载(overload)
方法重载(overload):同一类中,方法名相同,参数列表不同的一组方法就叫重载方法
输出
System.out.printlnEmpty();
System.out.printlnString(“hello”);
System.out.printlnInt(8);
参数列表的不同主要体现在三方面
1.数量不同
2.类型不同
3.顺序不同
四件套
1.理解题意,考虑边界问题
2.找出所有解
3.编写代码
4.测试
leetcode
构造方法及继承
构造方法
构造方法是一种特殊的方法
构造方法会给属性赋初值
构造方法会自动调用构造方法与类同名
默认的构造方法
1.每个类都至少有一个构造方法,如果不显式的定义,java编译器会自动为类创建一个无参的构造方法 即默
认的构造方法
2.默认的构造方法没有参数,没有方法体
3.如果开发者显式的定义了构造方法,那么java编译器将不会再生成默认构造方法
构造方法不返回值
Student(int no,String name,int age){
}
//构造方法前面不能加void (添加后会变成一个普通方法)
(void)Student(){
}
默认的构造方法
就近原则
就近原则:当访问不同作用域同名变量时 寻找最近的同名变量
this关键字
this代表当前对象的属性引用
this 用法:
this.属性
this.普通方法
this().构造方法
只有在其他的构造方法中才能使用this()来调用;
this()必须位于构造方法第一条语句;
Person p=new Person 一共做了几件事
1,开辟的新的空间
2,调用构造方法
3,返回引用赋值给p
匿名块
作用:将每个构造方法中相同的代码可以写在匿名块中 匿名块中的代码一定是在构造方法之前调用。
语法:
{
//代码
}
关于构造方法的小结
Person p=new Person(); //一共做了三件事
1.在堆中开辟内存空间
2.调用构造方法,为属性初使化
3.将引用返回给p;
包管理
照片
d:/照片/男朋友/男朋友1
/
语法格式
package com.huayu.oop;
导包
import com.huayu.oop.*;
import com.huayu.oop.Person;
继承
继承是面向对象编程的最重要的特性之王一,它可以简化类的设计,利用的原有的类来创建新的类
class Person{};
class Student extends Person{
}
关于继承的总结
1.java中,只支持继承
2.子类继承父类的属性和方法,并且可以增加新的属性和方法
3.使用extends关键字来继承
4.是否可以使用继承 ,可以通过Instanceof 来判断
方法重写
方法重写(override,overwrite):在继承关系下,子类覆盖父类的方法覆盖时,要求方法名,参数,返回值都相同
关于继承的小结
1.父类有的,子类一定有
2.父类没有的,子类可以扩展
3.父类有的,子类可以更改
super关键字
super代表父类对象的引用
通过super关键字,再子类中可以
多态和封装
面向对象的高级特性
封装
继承 :复用
多态
多态
多态:同一类事物,可以拥有不同的形态
动物:吃,喝,行走
狗:
猫:
蛇:
//子类的对象可以替代父类的对象进行使用
Student s=new Student();
Person p=s;
父类 s=new 子类
编译时类型
//当我们使用多态时,定义变量时使用的类型称为编译时类型 我们在使用方法和属性时,只能使用编译时类型
//提供的属性和方法
Person p=new Student();//此时,编译时类型是Person
Animal a=new Dog(); //编译时类型是Animal
a=net Cat();
a=new Fish();
a=new Bird();
运行时类型
//当我们调用多态的方法时,执行期间,调用的是运行时类型的方法
Animal a=new Dog(); //编译时类型是Animal,运行时类型是Dog
a=net Cat(); //编译时类型是Animal,运行时类型是Cat
a=new Fish(); //编译时类型是Animal,运行时类型是Fish
a=new Bird(); //编译时类型是Animal,运行时类型是Bird
类型转换
downcast:向下转型
upcast:向上转型
向上转换:直接转换无风险
向下转换:有风险例如将,Animal转成Dog就是向下转型,向下转型有风险,建议转型前,使用instanceof来判断 否则可能
会产生ClassCastException(类型转换异常) 异常
封装
java中,处处皆封装 主要表现在三方面?
1.类就是一个封装体,类中封装的属性,方法
2.方法也是一种封装 (方法中封装的是代码)
Random r=new Random();
r.nextInt(10);
3.通过访问修饰符可以改变访问权限
访问修饰符
类内部 | 同包 | 不同包的子类 | 不同包的非子类 | |
---|---|---|---|---|
private | 是 | 否 | 否 | 否 |
default | 是 | 是 | 否 | 否 |
protected | 是 | 是 | 是 | 否 |
public | 是 | 是 | 是 | 是 |
修饰符
final
final修饰属性,类,方法
它可以修饰,属性,变量,参数,只能赋值一次 不能被修改
修饰类:不能被继承
修饰方法:不能被重写
static
static修饰属性,说明当前属性是的类属性,只存在一份整个类共享
并且可以直接通过类访问。
属性:类属性 类名,属性名
方法:类方法示例
定义一个学生类,为学生自动生成学号,即创建的第一个学生,学号是1,第二个学生,学号是2
public class Student {
int stuno;
String name;
int age;
public Student(String name, int age) {
}
public void showInfo() {
System.out.println("学号:" + stuno + ",姓名:" + name + ",age:" + age);
}
public static void main(String[] args) {
Student s = new Student("王千金", 18);
Student s1 = new Student("王万两", 18);
Student s2 = new Student("王大锤", 19);
}
}
方法:
1.被static修饰的方法被称为类方法,调用类方法时无须创建对象,可以通过 类名.方法名()来调用
2.在static方法中,只能实现静态成员,不能使用非静态成员
3.在static方法中,也不能使用this,super关键字
static 返回值类型 方法名(){
//方法体
}
静态块
static块
语法:
static{
//代码
}
什么时执行:当类加载,初使化时,会自动调用静态块中的代码,因为每个类只加载一次,因此static{}只
被调用一次
加载顺序
静态成员和static块
👇
普通成员和非static块
👇
构造方法
加载顺寻
父类静态成员和static块
👇
子类静态成员和static块
👇
父类普通成员和非static块
👇
父类构造方法
👇
子类普通成员和非static块
👇
子类构造方法
单例模式
设计模式:Design partten
解决某些设计问题所采用的套路,有点类似于三十六计
目前设计模式一共有23种
一共分为三类
1.创建型
2.结构型
3.行为型
**单例模式:**Singleton
解决的问题:某个类,只允许产生唯一的实例
解决的方法
1.将构造方法定义成私有
2.定义一个同类型的静态的属性
3.定义一个public的静态方法,用来返回唯一的实例
单例模式 的两种类型
1.饿汉式
2.懒汉式 (lazy)
private static Singleton s=new Singleton();
/*String name;
String time;*/
private Singleton(){
/*System.out.println("创建单例模式: ");
System.out.println("进程分别有");
System.out.println("1");
System.out.println("2");
System.out.println("3");
System.out.println("4");*/
}
public static Singleton getinstance() {
return s;
}
/*public void close() {
System.out.println("关闭程序");
} */
抽象类与接口
abstract
abstract是一个修饰符
可以修饰方法和类
类:抽象类,不能被实例化
方法:抽象方法,让子类重写 如果子类不重写,子类方法也是抽象方法
抽象方法没有具体的实现抽象方法只有定义,没有方法的实现
如果一个类有抽象方法,那这个类一定是抽象类
如果子类不重写方法,那这个子类还是抽象类
接口
1.java中不支持继承,但通过接口,可以实现多继承的效果
2.接口是一个特殊的抽象类 接口中只能有抽象方法和public static final属性
3.接口使用 interface来定义
接口与类
接口通常代表一种能力,抽象类通常代表一个概念
接口:able:
会飞的
发光的
吃肉的
抽象类:
动物
交通工具
图形
找你妹
发光
会飞的
带尖的
交通工具
飞机
会飞的 a=new Plan();
=new 天使();
=new 蝙蝠();
=new 萤火虫();
接口与抽象类的区别
1.接口是一个特殊的抽象类,只有public static final 属性及抽象方法
2.一个类只能有一个父类,但一个类可以同时实现多个接口
3.类和类之间是单继承 ,但接口和接口之间可以多继承
interface C extends A,B
4.抽象类通常表示一个概念,而接口则表示一种能力
类和类之间的关系
主要有三种
1.继承
2.关联
3.依赖
关联又可以细分为
1.聚合
2.组合
继承
子类拥有父类的属性和方法
判断两个类是否是继承关系 is 即 子类 is 父类
代码: class 子类 extends 父类{}
实现
一个类可以实现多个接口
代码: class 类 implements 接口
依赖
两个类之间关系是临时发生的,即做某一件事时才产生联系,这种关系就是依赖
判断方法 : use;
代码:
两种形式
class Person{
public void eat(){
Spoon s=new Spoon();
}
public void attack(Weapon w){
}
}
关联
关联:一种强依赖,比依赖的关系更强,是一种稳定的关系
判断: has
代码:作为别外一个类的属性来存在
聚合
聚合是关联的一种特例,体现整体和局部的关系 整体和局部之间没有共同的生命周期
组合
聚合是关联的一种特例,体现整体和局部的关系 整体和局部之间有共同的生命周期
设计思想
高内聚,低耦合
内部类
可以将类的定义放在其它的类中,这种类叫内部类
内部类一共有四种,分别是
-
静态内部类
-
成员内部类
-
匿名内部类
-
方法内部类
静态内部类
静态内部类可以使用外部类的静态成员
public class A {
static int a=9;
String name="人";
//静态内部类
static class B{
public void getB() {System.out.println(a);
}
}
}
//test
public class TestA {
public static void main(String[] args) {
//创建一个内部类的对象
A.B b=new A.B();
b.getB();
}
}
成员内部类
在一个类的内部定义另外一个类,内部类可以使用外部类的非静态成员
public class Outer {
String name="outer";
class Inner{
public void getInner() {
System.out.println(name);
}
}
}
//test
public class TestA {
public static void main(String[] args) {
//创建一个外部类的对象
Outer o=new Outer();
//创建o的内部类对象
Outer.Inner i=o.new Inner();
i.getInner();
}
}
方法内部类
匿名内部类
有时,我们定义了一个内部类,使用这个内部类时,只实例一个对象 此时,就可以将定义类和实例化
对象,两个操作合到一起,这个就是匿名内部类
使用匿名类的条件是,此类必须实现一个接口或继承一个抽象类
1.定义一个类
class A(){
}
2.只实体化一次
A a=new A();
Usb u=new Usb() {
@Override
public String getData() {
// TODO Auto-generated method stub
return "这就是匿名内部类,看着有点不舒服。";
}
};
c.connect(u);
常用类
lang包
lang是java中使用最广泛的包,全称是java.lang 此包不需要手动导入,即可使用此包中的所有类
此包中常用的类有
System
Object
包装类
Math
字符串
Thread等
System类
//System 类包含一些有用的类字段和方法。它不能被实例化。 final修饰的类不能被继承
//常用方法:
System.out.println();
System.err.println();
System.in;
System.exit(0);
System.arraycopy()
System.gc()
System.currentTimeMillis()
包装类
java,为每个基本数据类型都定义了与之对对就的类,这些类就叫包装类
Boolean
Byte,Short,Integer,Long
Float,Double
Character
包装类与基本数据类型是可以相互转换的
基本数据类型-》包装类 :装包
包装-》基本数据类型: 拆包
Math
Math类:包含了所有用于几何和三角的浮点运算方法。Math类是final的,其中所有方法都是static的。
object类
Object类是所有类的类的父类 此类中下定义所有类都拥有的方法
equals():比较
toString():转成字符串
hashcode():哈希码
getClass():获得当前对象的类
clone():克隆
finalize():垃圾回收前执行的方法
notify()
notifyAll();
wait();
hashcode方法
hashcode是一个int值
即可将任何长度的对象转换成固定长度的数字
hashcode的协定
1.如一个对象不改变,那么多次调用hashcode()方法,返回的结果应该相同
2.如果两个对象相等(equals()),那么两个对象的hashcode()一定相等
3.如果两对象不相等,那么hashcode也有可能相等,设计时,尽量不相等
equals方法
boolean equals(Object obj);
四个特性
1.自反性:a.equals(a); true
2.对称性:a.equals(b)==b.equals(a);
3.传递性:a.equals(b)=true,b.equals©=true,那么 a.equals©=true
4.一致性:a.equasl(b)的值,多次调用时,应该相同 (前提是,a和b都不改变)
另外 a.equals(null),永远为false
toString方法
将对象转成String
注意:
1.如果不重写,那么将会调用父类的方法,内容是 类名@hashcode()的十六进制
2.当调用System.out.println(s)方法,会自动调用s.toString()方法
**getClass()**方法
获得对象的类 Class 即,所用同类型的对象返回的是同一个类
String 类
字符串 Java是常用的类
字符串的特点
1.字符串是常量,不能改变
2.为了提升使用率,java对字符串进行了优化处理,即字符串池(String Pool)
常用的方法
int length():返回字符串的长度
int indexOf(int):返回某个字符位于串中的位置(下标)
int lastIndexOf(String):查找最后一个指定子串的位置
boolean isEmpty():判断某个字符串是否为空
boolean startsWith(String):是否以某个字符串开头
boolean endsWith(String):是否以某个字符串结尾
String toUpperCase():转成大写
String toLowerCase():转成小写
String trim():返回一个去掉前后空格的新串
String[] split(String);拆分字符串
char charAt(int):根据索引找字符
String replaceAll(String a,String b):将字符串中的a都替换成b,并返回一个新的字符串
boolean contains(String):是否包含另外一个子串
字符串类
字符串比较方法
boolean equals(String) 比较
boolean equalsIgnoreCase(String) 比较(忽略大小写(英文))
int compareto(String) 与另一个字符串比较大小
int comparetoignoreCase()
字符串池
因为String是java最常用的类,同时此类是常量(一旦定义,不能改变),因此,为了提高效率(节省内存),java中使用字符串池
String s="hello";
String s1="hello";
String s2="hello";
String s3="hello";
字符串转换
不同的类型之间是否能转换?
1 基本类型 (可转)c
2 不同类之间 需要有继承关系才能转
3 如果两个类型之间没有继承关系,有时也可以通过一些方法转换
integer parseInt()
String s="123";
//将String,s转成int类型
int i=Integer.parseInt(s);
System.out.println(i);
//将int 类型的i转换成字符串
String s2=String.valueOf(i);
StringBuffer
1.StringBuffer是字符串缓冲区,与String不同,内容是可以修改的
2.StringBuffer支持链式编程
3.与StringBuilder不同,它是线程安全的
4.StringBuffer与String是可以转换的
StringBuffer->String; sb.toString();
String->StringBuffer: StringBuffer sb=new StringBuffer(String);
常用方法
StringBuffer append():追加
StringBuffer insert():插入
StringBuffer delete(start,end):删除指定的子串
StringBuffer repalace(start,end,str):将指定位置的字符串替换成str
StringBuffer reverse():翻转字符串
StringBuilder
与StringBuffer基本相同,只是线程不安全
异常
异常概念
错误主要发生有两种
1 编译时发生错误
2 运行时错误 叫做异常java的异常分为两类
1 error jvm内部错误、资源耗尽
2 exception 其他编程错误或偶然的外在因素
异常的体系结构
Throwable
Error:错误
Exception:异常
RuntimeException:运行时异常
NullPointerException:空指针异常
ClassCastException:类型转换异常
ArrayIndexOutOfBoundsException:数组下标越界
ArithmeticException:数字异常
受检查异常
异常处理
java中处理异常的机制是:抓抛模型
try-catch-finally
try{
//代码1;
//代码2 出现exceptin2;
//代码3:出现exception3;
}catch(Exception1 e){
//处理代码1
}catch(Exception2 e2){
//处理代码2
}finally{
//finally
}
异常分类
1 运行时异常 runtimeException类和其子类
2 受检查异常 非runtimException区别:
运行时异常编译时可以不处理
受检查异常必须得处理
throws
当我们定义一个方法时,如果正确调用,可以返回一个结果,如果错误的调用,则应该抛出一个异常,这时,
可以使用throws来抛出某种异常的类型
public double getCircleArea(double r) thrwos Exception{
}
//MyArray; 10,11
public int get(int index) throws ArrayIndexOutOfBoundsException{
}
throw关键字
throw代表:手动抛出一个异常对象 格式是
throw new Excpetion();
throw主要用在方法中 throw有点类似return
throw和throws的区别
throws与throw的区别
1.throws放在方法后,说明此方法可能抛出某种类型的异常
2.throws后,放的是异常类型
2.throw 放在方法体中,throw后面放置的是异常对象,说明要手动抛出一个异常
工具类
java.util包,被称为工具包,也是java最常用的一个包
此包中主要有集合框架,日期,编码解码,国际化等
random类
Random类是随机数生成器,提供了很多用于生成各种类型的随机数的方法
Date 类
Date类主用来存储时间,精确到毫秒,内部是通过一个long值来进行存储的
Calendar
日历类:主要用来处理时间,例如,获取时间的某个部分,改变时间的某个部分 对时间进行加减操作等
1.实例化
Calendar c=Calendar.getInstance();
2.Date与Calendar的转换
Calendar->Date c.getTime();
date->Calendar c.setTime(date);
3.操作时间
获得某个部分
int get(int )
Calendar.YEAR=1;
SimpleDateFormat
SimpleDateFormat类是日期格式化的类,可以用来将指定格式的之符串转成Date,也可以将Date转换成指
定格式的字符串
用法
1.先实例化一个对象
SimpleDateFormat sdf=new SimpleDateFormat(“yyyy-MM-dd”);
2.使用 parse方法将字符串转成日期
Date d=sdf.parse(str);
3.使用format方法将日期转成字符串
String str=sdf.format(data);
集合框架
集合框架
集合:集合也被称为容器,也是一个对象,此对象中可以管理其它的对象(element)元素 例如数组就是一
个集合
集合框架:java中给我提供了很多集合类,接口和算法类,作为一个整体,被称为集合框架
集合框架有两个顶层接口,所有的集合类都是这两个接口的实现
Collection接口
1.是集合框架的顶层接口之一,没有直接的实现类
2.Collection有三个子接口,分别是List,Set,Queue;
3.三个子接口的特点如下
List:有序(有索引),可重复
Set:无序,不可重复
Queue:先进先出
Collection接口应该有什么方法?
CURD
boolean add(E):增加一个元素
boolean addAll(Collection):增加多个元素
void clear():清空
boolean isEmpty():是否为空
int size():返回元素的个数
boolean remove(E):删除一个元素
boolean removeAll(Collection):删除多个元素
boolean retainAll(Collection):保留多个元素
boolean contains(E):是否包含某个元素
boolean containsAll(Collection):是否包含某些元素
Object[] toArray():将集合中的元素转成数组返回
所有集合类中存储的不是对象本身,而是一个引用而已
泛型
泛型指的是数据类型的参数化
泛型可以解决两个问题
1.类型安全检查
2.消除强制类型转换
java中,集合框架中的集合类都支持泛型
如何使用
List<Person> list=new ArrayList<Person>();
算法类
集合框架中除了提供接口和实现类之外,还提供用于处理集合的算法类,算法类主要有
Collections:用于处理集合的算法类
Arrays:用于处理数组的算法类
Collections常用的方法
static void sort(List):对List中的元素按自然顺序进行排序
static void reverse(List):翻转集合中元素
static void shuffle(List):洗牌 (打乱顺序)
static E max(Collection):获取最大的元素
static E min(Collection):获取最小的元素
static void addAll(Collection coll,T...t):向coll中增加多个元素
static int binarySearch(List):二分查找
static void copy(List desc,List src):复制
Arrays常用的方法
static List asList(T...t):创建一个List,将添加多个元素
static T binarySearch():二分查找
static T[] copyRange(int[],start,end);
static void sort();
static String toString();
Comparable
Comparable是自然排序的接口,实现此接口的类,就拥有了比较大小的能力
此接口中的方法只有一个
public int comparareTo(T t){
}
返回值说明
正数:当前对象与比t大
0:当前对象与t相等
负数:当前对象比t小
Comparator
自定义的比较器
Comparator接口中包含一个方法
Comparator与Comparable的区别
1.Comparable为可排序的,也被称为自然排序或内部比较器,实现该接口的类的对象自动拥有可排序功能。
2.Comparator为比较器,也被称为外部比较器,实现该接口可以定义一个针对某个类的排序方式。
3.Comparator与Comparable同时存在的情况下,前者优先级高
ArrayList源码分析
transient Object[]elementData; //定义一个Object数组,用来存储数组的元素,此数组可以扩
容
//2.构造方法
public ArrayList(){
this.elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//给一个初使长度
public ArrayList(int initialCapacity){
if(initialCapacity>0){
this.elementData=new Object[initialCapacity];
}else if(initialCapacity==0){
this.elementData=EMPTY_ELEMENTDATA;
}else{
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
//3.add方法
public boolean add(E e){modCount++;
add(e,elementData,size);
return true;
}
private void add(E e,Object[]elementData,int s){
if(s==elementData.length)
elementData=grow();
elementData[s]=e;
size=s+1;
}
数组总结
数组的特点:元素之间的地址是连续的
get(index):时间复杂度是O(1)
set(index,E)😮(1)
add(index,E):时间复杂度是O(n)
remove(index)😮(n)
链表
//内部结节
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
Stack
Stack是栈 特点是先进后出
LIFO:last in first out
方法:
push:压栈
pop:弹出
peek:获得栈顶的元素
栈的用途:
悔棋
撤销
方法的调用
Queue
Queue是一个队列,它的特点是先进先出(FIFO)
双端队列
Deque =dubole ended queue
两端都可以插入和删除元素
方法如下
addFirst
addLast
removeFist
removeLast
offerFirst
offerLast
pollFirst
pollLast
集合框架2
Set
Set:是Collection的子接口,无序,不可重复
三个主要的实现类
HashSet:hash
LinkedHashList:有顺序
TreeSet:排序的,内部是树
Iterator
迭代器 用来从所有的Collection集合中遍历数组 提供三个方法
boolean hasNext():是否有下一个未遍历到的元素
E next():取出一个元素
void remove():删除正在取出的元素
//代码模版如下
Iteartor ite=collection.iterator();
while(ite.hasNext()){
E e=ite.next();
}
LinkedHashSet
LinkedHashSet是对HashSet的扩展,内部也是一个HashSet,但是按存入的顺序进行排列的
LinkdeHashSet中的元素也是不可重复的
SortedSet
SortedSet:是Set的子接口,具备排序的能力
TreeSet:是SortedSet的实现类,内部是一个树结构
Map
1.Map是集合框架中的另一个顶层接口 Map结构的特点是 kev-value
2.集合中,key 是不可以重复的
3.key 和 value的类型都是引用类型
常用方法
put(k,v):增加一对元素
putAll(Map):将map中的所有元素增加到集合中
v get(k):根据key,来查找value
remove(k):根据key,来删除元素(key-value)
int size():获取集合中元素的个数
boolean isEmpty():是否为空
clear():清空
boolean containsKey(k):是否包含某个key
boolean containsValue(v):是否包含某个value
#遍历
Set keySet():得到所有的key的集合
Collection values():获得所有value的集合
entrySet():获得所有的元素的集合(Entry(key,value))
//遍历的示例
Map<Integer, String> map = new HashMap<Integer, String>();
//增加
map.put(1,"james");
map.put(2,"jack");
map.put(3,"james");
map.put(4,"owen");
map.put(3,"scott");
//1.如何遍历集合 keySet
Set<Integer> set = map.keySet();
System.out.println(set);
for(
Integer k:set)
{
System.out.println(k + ":" + map.get(k));
}
//2.values
Collection<String> coll = map.values();
for(
String s:coll)
{
System.out.println(s);
}
System.out.println("----------------");
//3.key-value
Set<Entry<Integer, String>> es = map.entrySet();
for(
Entry<Integer, String> e:es)
{
System.out.println(e.getKey() + ":" + e.getValue());
}
HashMap的内部结构
1.key-value在内部被封装成了一个内部类 Node
2.HashMap中定义了一个Node类型的数组用来保存元素
3.Node还是一个单向链表 当链表中的元素超过8时,则转换成红黑树
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key; //key
V value; //value
Node<K,V> next; //下一个节点,Node是封装了key和value,同时也是一个单向链表
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
}
transient Node<K,V>[] table; //将所有的key-value对,即node,都存在table中,table是一个数组
//put方法
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K, V>[] tab; //table的引用
Node<K, V> p; //元素中的首个Node节点
int n; //table的长度
int i; //元素的下标 通过hash后,模运行(实际是 (n - 1) & hash])
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length; //重新分配长度,算出tal的长度
//如果元素中无值,则将Node放在索引为i的下标下
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K, V> e; //如果有相同的key,e存储的是重复节点的引用
K k;
//如果元素中的首Node与新节点相同 则
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode) //如果是树结点,则使用树节点的方式查找
e = ((TreeNode<K, V>) p).putTreeVal(this, tab, hash, key, value);
else {//遍历链表,如果有重复的,将重复的节点赋值给e,并break,否则,将新节点加到
链表尾部
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {//链表中最后一个结点
p.next = newNode(hash, key, value, null);
//如果长度大于8,则转成树
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
//如果有重复的,则不再比较
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;//指向链表的下一个元素,用来遍历
}
}
if (e != null) { // existing mapping for key 如果有重复的,进行替换
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)//根据onlyIfAbsend决定是否替
换
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
Hashtable
Hashtable 是一个古老的 Map 实现类,不建议使用
Hashtable 是一个线程安全的 Map 实现,但 HashMap 是线程不安全的。
Hashtable 不允许使用 null 作为 key 和 value,而 HashMap 可以
TreeMap
TreeMap 存储 Key-Value 对时,需要根据 Key 对 key-value 对进行排序。TreeMap 内部是同红黑
树来实现的。
TreeMap 的 Key 的排序:
自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对
象,否则将会抛出 ClasssCastException
定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进
行排序。此时不需要 Map 的 Key 实现 Comparable 接口