第一节 .变量
三要素:
数据类型
变量名
变量值
第二节.数据类型
8大基本数据类型
byte | short | int | long | float | double | boolean | char |
---|---|---|---|---|---|---|---|
1字节 | 2字节 | 4字节 | 8字节 | 4字节 | 8字节 | 一字节 | 2字节 |
字节类型 | 短整型 | 整型 | 长整型 | 单精度 | 双精度 | 布尔 | 字符 |
类型转换
自动类型提升
强制类型转换
自动类型提升,安全的,自动完成无需干预。
强制类型转换,不安全,手动完成。
byte>short>int>long>float>double
箭头右边变量,可以直接保存左边的变量,反之需要强转。
第三节、运算符
3.1 赋值运算符
符号: =
3.2 算术运算符
符号:+ - * / %模(取余)
注意:除法运算结果精度参考参与数的最高精度。如果参与数都是整数结果会被省略掉。
3.3 关系运算符
符号 > < >= <= == !=
3.4 逻辑运算符
符号:&& || !
运算法则: && 同真则真,一假则假 || 一真则真 同假则假 !取反
3.5 复合赋值运算符
符号:+= -= *= /= %=
3.6 自增自减
符号: ++ --
1. 符号可以位于 操作数前或者后面。
2. 无论在前或在后,只要执行完成,操作数要么+1 要么 -1。也就是说在前在后对对操作数讲影响是固定的。
3. 在前在后对于 表达式 的影响是有区别的,在前:先运算再赋值, 在后,先赋值再运算。
3.7 位运算符(了解)
&按位与 |按位或 ^异或 按位取反~ 左移<< 右移>> 无符号左移<<<
3.8 其他
符号:?:
三目运算符
第四节、流程控制
流程控制的作用是去组织程序代码,可以使程序安装一定的顺序进行执行,几乎所有的编程语言都具备这样的能力,同时基本分为三大种控制结构:
顺序结构
选择分支结构
1.IF 语句
2.IF-ELSE 语句
3.IF-ELSE-IF 语句
IF 嵌套
在IF 的内部可以 再使用IF结构,内部的IF 外部成立才执行。
4.switch-case
语法
switch( 变量 ){
case 值A: 语句;break;
case 值B: 语句;break;
......
default: 语句;
判断变量的值与case是否相等,如果相等则执行该case后的语句,一般每个case配有break退出switch结构。 如果都不相等,如果有default则执行default后的语句,default可选。
case 穿透: 如果一个case后缺省了break,那么程序会依次往下继续执行,不考虑与case是否匹配,直到执行到break才退出switch。
循环结构
重复执行某些语句。
- while
while( 条件表达式 ){
循环执行的语句
}
当条件满足时,执行循环体中语句,语句执行完成后,再次判断条件,周而复始,直到条件不满足退出。
- do-while
do{
循环执行的语句
}while( 条件表达式 );
现在执行 循环体,执行完后再判断条件是否满足,如果满足继续执行,周而复始,不满足则退出。
for 循环
for( 初始化变量 ; 循环条件 ; 迭代 ){`
循环语句;
}
第五节、开发工具
5.1 介绍
开发工具通常使用集成开发环境,提升开发效率,在Java领域比较有代表的 Eclipse (早期非常),IDEA(目前流行)
- Eclipse
- 开源免费
- 不够流畅,经常卡死,内存需求小。
- 基于插件来扩展功能, 其中myeclipse就是用 通过对Eclipse安装插件来扩展web开发。
- IDEA
- 收费软件
- 内存开销大,流畅,界面友好
- 有丰富的插件。
第六节、函数与方法
6.1 基本概念
基本概念: 实现特定功能的一段代码,可以重复使用。
6.2 定义语法
定义语法:
public static 返回值类型|void 自定义方法名([数据类型 变量名,...]){
若干语句;
[return value]
}
参数列表: 定义函数执行期间需要的变量,可以定义0个或多个,定义时没有具体值,只有类型,方法调用时为其赋值,称为形参。
返回值类型:用于规此方法,返回数据的类型,必须要一致,如果函数不需要返回值,声明为 void。
{ }函数体 :装函数的实现逻辑代码
返回值
[return value]
:如果返回值类型为void,就没有return。如果返回值有具体类型,这必须有return, 如果有返回值类型的函数 内部有分支,一定要保证,每个分支都有return 覆盖。
6.3 函数示例
定义一个 没有参数 没有返回值
public static void chineseSayHello(){
System.out.println("你好!");
System.out.println("我是渣渣辉");
}
定义一个有参数, 没有返回值
public static void sumOfNum( int n ){
int sum =0;
for(int i=0 ; i<=n ; i++){
sum += i;
}
System.out.println("sum:"+sum);
}
定义一个有参数 有返回值
public static String choujiang(int price){
if( price >= 10 ){
Random rd = new Random();
//随机编号
int i = rd.nextInt(10);
//奖品名字
String pjName="无";
//匹配奖品
switch (i){
case 0: pjName="冰箱";break;
case 1: pjName="娃娃";break;
case 2: pjName="电视";break;
case 3: pjName="洗衣机";break;
default:pjName="谢谢惠顾";
}
//返回
return pjName;
}else{
return "需要10元";
}
}
6.4 函数调用
函数调用,目的是使用定义好的函数功能,调用函数需要遵循调用规则。调用函数时,会把实参 赋值给 形参
要求实参的个数 类型 顺序 和形参一致,然后进入调用函数中,执行其中的代码语句,此时形参才有值。
调用语法
[类型 变量名=] 函数名([实参,...])
- 调用 没有返回值的函数
函数名([实参,…])
sumOfNum(100);
如果有参数需要给实参。
- 调用 有返回值的 函数
接收变量 = 函数名([ 实参,… ])
String jp = choujiang(10);
System.out.println(jp);
需要使用变量接收返回值 , 如果有参数需要给实参。
6.4 return 特殊用法
通常情况,return 只会出现在有返回值声明的函数中,其作用就是返回一个数据。特殊的,return 出现在void 声明的函数中,也是可以的,但是不同用于返回一个数据,其作用是结束方法执行。
public static void inputNum(int n){
if( n<100 || n>999 ){
return;
}
//100行的功能逻辑
System.out.println("这个三位数"+n+"好棒!");
}
6.6函数调用流程
从宏观看,调用一个函数,就会去执行函数中的语句,同时如果有参数的话,会把实参赋值给形参,当被调用函数中所有语句都执行完毕,这函数调用完成,程序回到调用出,继续往下一次执行。
从内存看,调用一个函数,会想线程栈中,压一个方法栈帧( 有局部变量表,方法出口 )当方法中的全部语句执行完毕,则移除栈帧,方法调用完毕。
6.7 递归
方法内部调用自身的一种行为。可以解决有规律且重复的问题,问题在于解决问题的方法就是本身,使用递归代码更精炼。
第七节、数组
7.1 概念
用于保存一组长度固定类型相同的变量集合。
7.2 定义数组
数据类型[] 数组名 = new 数据类型[长度]
示例:
int[] arr = new int[5];
示例:
double[] brr = new double[10];
示例:
String[] crr = new String[6];
数组是引用数据类型,占用两块空间,new 关键字的作用是去堆内存中去申请连续空间。
7.3 数组声明有初始化
数组也是变量,也可先声明,再实例化。
声明语法:
数据类型[] 数组名;
int[] arr;
实例化语法:
数组名 = new 类型[长度];
arr = new int[100]
7.4 元素访问
数组中的每个空间成为元素,对数组的每个空间存值或者取值叫做元素访问。数组元素访问,需要依靠下标完成,数组一旦实例化,下标就有了,从0开始 到数组 长度-1 ,如果使用超出范围的下标,将引发 ArrayIndexOutOfBoundsException 异常。数组的元素个数可以通过 数组名.length 来获得。
int[] arr = new int[4];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
// 可以看见 数组有4个空间,所以有4个元素,通过下标为每个元素空间赋值。
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
// 可以看见 通过变换下标,把每个元素都输出。
7.5 数组元素遍历
通常,数组的元素下标是连续变化的,这一点恰好可以联系到循环,可以使用循环的计数器来充当下标,这样就可遍历出数组的全部内容。
int[] arr = new int[4];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
// 可以看见 数组有4个空间,所以有4个元素,通过下标为每个元素空间赋值。
/*
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
*/
// 可以看见 通过变换下标,把每个元素都输出。
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
7.6 基本数据类型与引用数据类型
java 中基本数据类型与引用类型在内存分配上的区别
值传递 VS 地址传递
1. 基本数据类型为值值传递 , 引用数据类型为地址传递。
2. 数组类型可以 设计为函数的参数 和返回值
记住: 数组参数,接收的是 实参数组的地址 数组返回值,返回的是数组的地址。
3. 数组的扩容:
1. 手动 , 对应下标赋值
2. System.arrayCopy(原数组,原数组起始下标,新数组,新数组起始下标, 拷贝个数)
3. Arrays.copyOf(原数组,新数组的长度 ) 返回了新的数组,需要接收。
4. 可变参数:
函数名(数据类型... 参数名){
//使用参数,当做数组使用即可
}
5. Arrays.toString(数组)返回字符串
7.7 数组排序
- 冒泡
// 冒泡 排序:
/*
* 思想: 两两比较,把较大的往后交换。全部元素比较完毕为1趟,选出了一个最大的。 ,[8 7 6 5 4 3 2 1 9 ]
* 重复以上步骤,直到全部排好。 [7 6 5 4 3 2 1 8 9 ]
* 有多少趟? 基本有元素个数决定 比如10 需要 9
* */
public static void maopao( int[] arr ){
//完成排序逻辑
for( int i = 0; i < arr.length - 1 ; i++ ){ //控制趟
//嵌套内循环
for(int j = 0;j < arr.length - 1 - i; j++ ){
//两两比较大小
if( arr[j] > arr[j+1] ){
//交换
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
//System.out.println( "第"+i+"趟:"+ Arrays.toString( arr) );
}
}
- 选择排序`
// 选择 排序:
/* {1,10,32,56,21,36,9,45,22,67,30}
* 思想: 先假设出最小值,为当前趟数对应下标值,然后依次和其他未元素进行比较,如果发现存在更小的元素,记录下这个最小值的下标。
* 一趟结束后观察 min 下标有无变化,有变化则交换 无则不管。
* */
public static void choose(int[] data ){
for(int i=0;i<data.length;i++){ // 控制趟数。
//假设当前趟数出的元素就是最小的
int min = i;
//用假设的这个元素 依次和后续元素比较。
for(int j=i+1; j<data.length;j++){
if( data[min] > data[j] ){
min = j; //如果有更小的记录下标
}
}
//观察是否有变化
if(min !=i){
//交换
int temp = data[min];
data[min] = data[i];
data[i] =temp;
}
}
}
- JDK 工具排序
java.util.Arrays.sort(T[] arr)
7.8 二维数组
7.81 概念
二维数组,指的是一个数组元素的类型又是一个数组,数组的数组。
7.82 定义语法
数据类型[][] 数组名 = new 数据类型[高维长度][低维长度]
示例:
int[][] arr = new int[3][4]
int[][] brr = new int[3][]
//int[][] crr = new int[][3] 错误必须指定高维度长度,可以省
静态初始化:
int[][] drr = { {1,2,3},{23,44},{123,456,789} };
7.84 杨辉三角
public static void main(String[] args) {
int[][] data = new int[10][10];
//初始化杨辉三角数据
for( int i=0; i<data.length;i++ ){
for(int j=0;j<=i;j++ ){
//填值
//第1列 固定为 1 最后一列 固定为1
if(j==0 || j==i ){
data[i][j]=1;
}else{
// 当前元素为 正上方元素 与 正上方前一个元素的和
data[i][j] = data[i-1][j]+ data[i-1][j-1];
}
}
}
//遍历输出
for (int i=0;i<data.length;i++){ // 10 -i =
// 打印空格
System.out.format("%"+ (10-i)*2 +"s","");
// 打印数字
for(int j=0;j<=i;j++){
System.out.format("%4d", data[i][j] );
}
System.out.println();
}
}
第八节、面向对象
OOP(Object Oriented Programming) 面向对象的程序设计,指的是一种编程思想(思维),相较于面向过程,面向对象对功能的设计有一定简化面向对象,不关注问题细节实现本身, 是一种把业务功能实现委派个某些对象来实现,我们的关注点是对象。
面向过程:(Procedure Oriented)面向过程的程序设计思想,关注的是功能实现的具体细节。
以生活为例:
理发:
Procedure Oriented: 1.找到头, 2.找推子,3 选发型,4剪.....
Object Oriented Programming: 找Tony...
面向对象与面向过程并不冲突,而是互补,面向对象中对象的方法逻辑就是面向过程的思想。
8.1 基础概念
- 对象
一个切客观存在的事物都可以视为对象,对象拥有具体的特征和行为。
- 类
类是一组具有相同或相似事物的统称,用于定义对象的共性属性和行为。
- 类对象关系
类是对象的模板,对象是类的具体实例。
8.2 定义类
8.3 创建对象
8.4 实例变量
直接定义在类中,方法以外的变量为实例变量,实例变量是为每个实例声明的变量,通常设计类的时候用于描述该类事物特征
8.5 实例方法
类中定义的实例方法,是由实例(该类的实例) 调用的方法,通常设计类的时候用来描述该类事物的行为功能。
定义语法:
修饰词 返回值类型 方法名( 参数列表 ){
方法逻辑
}
class Teacher{
//在类中定义实例方法
public void teach(){
System.out.println("今天来学习面向对象吧");
}
}
实例方法 调用:
Teahcer obj = new Teacher();
obj.teach();
8.6 方法重载
当存在同一个行为可能有多种不同的实现方法时,通过方法重载机制,可实现多个方法使用相同的名字,通过参数来区分方法调用的效果,对代码的灵活性有显著提升。
方法重载要求:
- 同一个类中, 方法名相同。
- 参数列表不同(类型 个数 顺序 不完全相同)
- 与返回值类型,参数名字无关。
class Demo{
// 计算 n 以内的整数和 sum(int n)
public double sum(int n){
int sum = 0;
for(int i=0;i<=n;i++){
sum += i;
}
return sum;
}
// 计算 m n 内的整数和 sum(int m, int n)
public double sum(int m , int n){
int sum = 0;
for(int i=m;i<=n;i++){
sum += i;
}
return sum;
}
}
class TestDemo{
public static void main(String[] args){
Demo obj = new Demo();
double s1 = obj.sum(10); // 调用 public double sum(int n)
double s2 = obj.sum(10,20);// 调用 public double sum(int m , int n)
}
}
调用重载方法,是通过给定的 实际参数 去匹配 最佳的方法执行。
8.7 构造方法
构造方法,又叫构造器,作用是创建对象,为属性赋初值。
特点:
- 没有返回值类型(注意不是写void)
- 构造方法名字 与 类名一致。
- 当没有自己编写构造方法时,系统提供一个默认构造方法(无参数)。
- 构造方法只能通过 new 触发调用,不可以使用句点调用。(this用法除外)
public class Student {
//属性
String name;
int age;
String sex;
String major;
//无参数构造器
public Student(){
System.out.println("Student()");
}
//全参数构造器
public Student(String sname, String ssex, int sage, String smajor){
name =sname;
age=sage;
major = smajor;
sex = ssex;
}
}
8.8 构造方法重载
构造方法也是方法同样允许重载使用,一个类提供多种参数的构造器,方便后续创建对象时 有更多的初始化属性选择。
public class Student {
//属性
String name;
int age;
String sex;
String major;
//无参数构造器
public Student(){
System.out.println("Student()");
}
public Student( String sname ){
name = sname;
}
public Student(String sname , String ssex){
name = sname;
sex =ssex;
}
public Student(String sname, String ssex, int sage, String smajor){
name =sname;
age=sage;
major = smajor;
sex = ssex;
}
}
创建对象时,由参数去匹配 要使用哪个构造器。
8.9 this 关键字
this 是一个关键字,在类中无需声明直接使用,是一个引用,指向当前对象(谁调用就指谁),有两个作用。
- 在实例方法或者构造器中,用于区分实例变量和局部变量
// 有参构造器
public Movie(String movieName, String director, int time) {
this.movieName = movieName;
this.director = director;
this.time = time;
}
- 调用本类构造器
public Movie(String movieName, String director ) {
this.movieName = movieName;
this.director = director;
}
// 有参构造器
public Movie(String movieName, String director, int time) {
this(movieName,director);
this.time = time;
}
因为构造方法不可以直接调用,通过this( ) 或者 this(参数) 调用,同时这种调用必须位于本构造器第一行。
第九节、面向对象三大特征
面向对象具备三大特性,分别是封装 继承 多态,几乎所有的所谓设计模式都是以此为基础。这些特征是面向对象语言所具备的,面向过程不支持此语法。
9.1 封装性
1 继承概念
隐藏对象内部细节,控制对象的修改访问权限。
2 封装实现方式
private 修饰符 ,在属性 和 方法前声明,表示此属性和方法为私有,只能在本类中访问。
为private 属性提供 公共访问方法。
9.2 继承
1 继承概念
两个类A,B存在 A is a B 关系,可以把共性属性和方法定义在B类中,通过继承原理,A类可以重用B类中的共性代码和属性。继承的思想是重用和扩展,一个类可以通过继承获得 属性 和 方法,同时也可以扩展出新的属性和方法。
2 继承语法
class A extends B{
}
这里 A 为子类 B为父类
3 不可继承内容
一个类继承另一个类后,并不是全盘继承父类全部内容,有些内容是不可以继承的比如:
1 构造器 不可继承
构造器是构造当前类对象的方法,要求与类同名,子类无法继承父类的构造器来当自己的构造器,子类必须自己定义本类的构造器。
2 私有属性 不可继承
父类的私有属性,由于封装性问题,只能在父类本类中使用,子类无法直接继承使用。
3 父类中default 属性和方法 子类在非同包 不可继承。
由于default 的访问性质,极限是同胞,跨包无法访问,故子类不可直接继承使用。
4 访问修饰符
java 中提供了 3个关键字,共4种访问级别控制:
-
private
表示私有 ,被他修饰的属性 方法 为私有, 只能在本类中访问。
-
default
属性方法前,不写访问修饰符 表示默认,只能同包访问。
-
protected
表示 受保护, 兼容 default 性质, 同时扩展了 异包子类可访问。
-
public
表示公开, 任意位置可以访问。
总结:private -> default -> protected -> public 访问级别从严到宽。
5 方法重写
当 子类重父类继承到方法,但是继承来的方法并不使用,或者并不能达到子类的要求,此时,子类可以对方法内容重新编写实现,这个行为 称为方法 重写 或者 重载。
具体要求:
- 子类 重写方法时,要求 签名一致 (返回值 方法名 参数列表)
- 子类 重写方法是, 要求 访问权限 不能更严。
6 .继承中对象创建过程
在存在继承的体系关系中,创建子类对象,比先创建父类对象,简单理解就是一个完整的子类对象中,包含一个父类对象实例,这个实例一般在子类中通过super访问。请思考几个问题?
问题1:为什么要创建子类对象?
答: 因为子类需要继承父类的实例变量,二实例变量必须存在实例,才会存在,所以必须以一个父类的实例来承载实例变量空间,从而被子类继承并使用。
问题2:什么时候创建的父类对象?
答: 在子类的构造器中,第一行代码默认会去调用父类的无参构造**【调用方式super()】** 写不写都有。当然也可调用父类有参构造。
7.super关键字
super 关键字是一个关键字,可以在子类中直接使用,表示的是子类对象空间中的那个父类对象引用。super 存在两个作用:
- 可以用来区分 父类和子类中同名的实例变量和方法
使用 super.属性名 或者 super.方法名
- 可以用来 调用父类构造器,用户初始化从父类继承来的那部分属性(尤其是在父类属性被私有化时)。
super() 或者 super(参数)
在子类构造方法中 使用super() 或者 super(参数) 务必保证调用位于当前构造器的第一行
9.3多态
1 概念
多态是,面向对象三大特征中的最后一个特征,语法很简单,实际上只是一种用法。 总结一句话就是, 父类类型的引用可以指向任何子类对象。
Animal animal = new Dog();
Animal animal = new Cat();
这里 Dog 和 Cat 都是 Animal 的子类。所以多态是建立在继承之上的一种特性。没有继承就没有多态。
2 编程现象
一旦使用多态用法,那么通过父类类型的引用就只能调用 在父类中声明的属性和方法, 子类特有的方法无法调用
这样的好处是,屏蔽了各种子类的不同点。通过多态,只能观察(调用)到子类的共同行为。
public static void main(String[] args){
Person person = new Student("小红",20);
//可以调用Person父类中定义的方法
person.eat();
person.sleep();
person.sayHello();
//不可调用 子类特有的属性和方法 ,编译看左边,运行看右边
//person.lookAll();
//person.study();
}
//这里 Student 是 Person 的子类。
3 多态的应用场景
多态通常就有两个应用场景,这并不是直接体现的,而是隐含体现的。
-
父类类型做
父类类型做参数,可以保证各种子类对象都可接收。
//实例方法: 多态运用场景1, 父类类型作为参数,可以接受不同子类对象。 public void travel(Transport transport, String start, String end ){ System.out.println(age+"岁的"+name+","+job+"乘坐"); transport.run(start,end); }
这里 Transport transport 父类类型参数,使得 Subway对象 Car对象 AirPlane对象都可接收。
-
父类类型做 参数类型
返回值的类型为父类类型,这样可以使得方法可以返回 各种子类对象实例。
//实例方法:多态运用场景2, 父类类型作为返回值类型。可以返回不同子类对象 public Food buy(){ Food food = null; Random rd = new Random(); int i = rd.nextInt(3)+1; switch (i){ case 1: food = new Mo("肉夹馍");break; case 2: food = new HotPort("桥头火锅");break; case 3: food = new Beef("牦牛肉干");break; } return food; }
这里 方法返回值类型为Food ,使得 Mo对象 Hotport 对象 Beef 对象都可返回。
3 类型转换
- 自动类型提升
引用数据类型转换分为向上转型,向下转型,向上转型也叫自动类型提升,它就是多态的核心。简单的说就是可以直接把一个子类对象用父类类型的变量来保存。
Animal animal = new Dog();
这里 new Dog() 就是一个对象, 而这个对象被保存到一个 Animal的引用中。
- 强制类型转换
把一个父类类型的引用 还原成它真实指向对象的类型的过程
Animal animal = new Dog();
Dog dog = (Dog)animal;
需要注意的是 务必保证 强转的合法性,因为父类类型引用只能转换成它真实指向对象的类型,如果不是会报错比如:
Animal animal = new Dog();
Cat cat = (Cat)animal;
这里将会引发 java.lang.ClassCastException 。因为 animal 这里真实指向的对象为 Dog 而不是 Cat,不能强转。
4 类型判断
因为强制类型转换存在安全性问题,所以强制转换前,需要提前判断使用 instanceof 关键字判断。
语法为 引用变量 instanceof 类型
如果前者是后者类型 返回true 否则 false
Animal animal = new Dog();
if ( animal instanceof Dog ){
Dog dog = (Dog)animal;
}
if ( animal instanceof Cat ){
Cat cat = (Cat)animal;
}
第十节、三大关键字
1. abstract 关键字
概念
abstract 意思为抽象的,可以来描述抽象的事物,和抽象的行为,在程序中也就是可以定义抽象类和抽象方法。
抽象类本质还是类,作用还是描述一类事物,只是这类事物比较抽象(某些行为,不够具体 很难实现)
抽象类成分
* 抽象类中可以定义什么呢?
*
* 定义属性
*
* 定义构造器
*
* 定义实例方法
*
* ...............
* 可以这么说,普通类有的成分它都具备,不能实例化本身的实例。
抽象类的意义
* 抽象类存在的价值?
* 1 . 可以作为父类使用,提取共性属性和行为。
* 2 . 可以建立多态使用方式
抽象方法
* 抽象方法:
* 一般在父类中,这个方法无法给出具体实现。抽象方法使用 abstract修饰,没有方法体。
*
* 特点: 1. abstract修饰,没有方法体。
* 2. 抽象方法所在类,必须是抽象类。
* 3. 继承抽象父类,必须重写全部的抽象方法,除非子类也是一个抽象类。
2 static 关键字
学习static 可以从以下 层次来。
- 第一个层次
static 是一个关键字,可以修饰属性和方法,被static 修饰的属性和方法称为,静态属性和静态方法,区别于实例属性,静态属性,只有一份,通过类名访问。 同理静态方法也是通过类名直接调用。 总之静态属性和方法不依赖于对象。而是依赖于类。
- 第二个层次
静态方法中,可以访问静态属性,静态方法。不可访问实例属性,和实例方法,以及实例相关的this super 关键字。
- 第三个层次
静态代码块,用于初始化静态属性的代码块,类加载时执行,一个类只加载一次,所以静态代码块,也只会执行一次。关于静态属性的初始化问题,根据赋值语句的先后顺序来判断。
一个类加载后, 在准备阶段开辟了静态属性的空间,但是并不是立即赋值的。
static int age =10 ; 即便是写成一句话,也是分为两个阶段。
准备 : int age =0
初始化: age =10;
3 final 关键字
final 意为最终的,表示不可"更改"的含义,可以修饰 类,方法,变量(属性)。
使用final 控制一个方法不可以被重写。
abstract 可不可以与 private static final 关键字连用
不可以。矛盾。
第十一节、接口
11.1 概念
什么是类,描述一类事物(普通事物 ,从属性行为来描述),如果某些事物非常抽象,还需要抽象类来描述。总的来讲类都是描述事物的,并且非常关注属性和行为。接口也是描述一类事物的,但是这类事物往往比抽象事物还抽象,以至于只能去描述事物的行为,且行为还是一个抽象的。
升华理解: 类是用来统一家族行为特征的工具, 接口是用来统一非家族行为的工具。
11.2 接口定义
接口定义使用 interface
关键字定义,需要注意的是接口中定义的成分。
成分:
- 静态常量
- 抽象方法
- 默认方法(1.8新增)
- 静态方法(1.8新增)
**注意:**接口中不可定义 构造器 代码块 静态代码块,因为接口不可创建本身实例,也不存在属性初始化。
11.3 实现接口
接口的存在的意义就是被类实现,一个类实现一个接口,那么意味着这个类将重写此接口中全部的抽象方法。
实现语法
class A implements 接口[,接口,...]{
}
Java 中接口是多实现的,一个类可以实现多个接口。
11.4 接口引用
接口虽然不能实例化自身对象,但是可以实例化实现类对象,实现多态。
接口 引用 = new 实现类();
11.5 接口多态
接口多态和继承多态效果是一样的,都是 实例化下一级的类,通过父级的引用都只能调用父级中声明的方法。
//蓝牙接口
public interface IBluetooth {
//连接
public abstract void connect();
//断开
public abstract void close();
//发文件
public abstract void send( String fileName );
}
//充电接口(能力)
public interface ICharge {
//定义静态常量
public static final String varsion="Qi3.0";
//定义一个快充功能
public abstract int fastCharge();
}
//实现类
public class Phone implements ICharge, IBluetooth {
private String name;
private int ram;
private int rom;
public Phone(String name, int ram, int rom) {
this.name = name;
this.ram = ram;
this.rom = rom;
}
public void show(){
System.out.println(name);
System.out.println(ram+"GB");
System.out.println(rom+"GB");
}
//自己扩展的方法
public void call(String tel){
System.out.println("拨号"+tel);
}
//重写全部接口中全部抽象方法
@Override
public void connect() {
System.out.println(name+"连接到 蓝牙...");
}
@Override
public void close() {
System.out.println(name+"断开蓝牙.....");
}
@Override
public void send(String fileName) {
System.out.println(name+"用蓝牙发送"+fileName);
}
@Override
public int fastCharge() {
return 60;
}
}
多态测试
public static void main(Striing[] args){
System.out.println("---------------以下代码测试接口引用和多态-------------------------");
ICharge phone2 = new Phone("Iphone 12 Pro",6,128);
int va = phone2.fastCharge();// 只能调用 ICharge 接口中声明的方法
System.out.println(va);
IBluetooth phone3 = new Phone("MI",8,64);
phone3.connect(); // 只能调用 IBluetooth 接口中声明的方法
phone3.send("java入门到放弃.pdf");
phone3.close();
System.out.println("--------------以下代码测试接口向下转型-------------------------");
ICharge phone4 = new Phone("ViVO",6,128);
int dl = phone4.fastCharge();
System.out.println("电量"+dl);
Phone xx= (Phone)phone4; // 向下转型后调用实现类特有的方法
xx.connect();
xx.send("mysql 从删库到跑路.pdf");
xx.close();
}
11.6 接口继承
接口与接口是一种继承关系,java中接口是多继承性的,一个接口可以继承多个接口,继承接口是为了让重用父接口中的抽象方法。
interface A{
void a();
}
interface B{
void b();
}
interface C extends B,A{
void c();
}
C接口将具备3个抽象方法。如果X类实现接口C 那么它将重写 a() b() c() 三个方法。
11.7 常量接口
一个接口中只有静态常量,这个接口就是一个常量接口,使用常量接口可以提高代码的规范性。常量接口本质上就是存为了保存一些常量值的接口。消除编码中直接使用字面量。
通常运用常量的方法,与常量接口都是一起设计的。
11.8 接口回调
接口回调是接口的一个比较高级的用法,它出现的原因通常在于,当我们需要封装一个通用方法时,发现,这个通用方法中,存在某些逻辑存在差异性,无法封装,此时可以为方法声明一个 接口类型的参数,把无法封装的逻辑交给接口引用调用方法处理。而我们只关注通用逻辑部分即可。
interface ILife{ // 定义一个人经历的接口
//记录人经历的抽象方法
void record();
}
//不同人的经历实现类
class SDXLife implements ILife{
@Override
public void record() {
System.out.println("1998生人");
System.out.println("考入北京大学学习java");
System.out.println("毕业进入阿里巴巴工作");
}
}
class LCLife implements ILife{
@Override
public void record() {
System.out.println("李超1997生人");
System.out.println("考入北京千锋java学院");
System.out.println("立人科技园编程");
}
}
public class Master {
//司仪介绍红白喜事的通用方法( 需要介绍 当事人的生平事迹,但是每个人的经历是不一样的,无法封装,所以这里使用接口回调 )
public static void talk( ILife life ){
System.out.println("大家好,欢迎各位宾朋!"); //可封装的逻辑
life.record(); //不可封装的逻辑 交给接口调用方法解决。
System.out.println("大家自由活动吧,5楼棋牌室!");//可封装的逻辑
}
public static void main(String[] args) {
talk( new SDXLife() ); //调用方法时传入不同 人生经历对象
System.out.println("--------------------");
talk( new LCLife() );
}
}
11.9 接口作为设计工具
面向接口编程,以接口为中心,先不想功能的实现,而是想有什么功能,用接口来组织方法。先定义接口,后做实现。
//统一描述APP 功能
public interface IApp {
//第一期
void massage();
void voice();
void friend();
void shake();
}
//实现APP 功能
public class MyApp implements IApp {
@Override
public void massage() {
System.out.println("massage");
}
@Override
public void voice() {
System.out.println("voice");
}
@Override
public void friend() {
System.out.println("friend");
}
@Override
public void shake() {
System.out.println("shake");
}
}
11.10 解耦
程序设计遵循 高内聚 低耦合 性质一样关联或相似的功能要集中,模块间的关联性要尽量低。
耦合度,两个模块的关联程度。在开发中常常使用接口实现解耦。
//模块B
public interface ModuleB {
void nb();
}
public class ModuleB1 implements ModuleB {
@Override
public void nb() {
System.out.println("张三实现的nb方法");
}
}
public class ModuleB2 implements ModuleB {
@Override
public void nb() {
System.out.println("李四实现的nb方法");
}
}
//模块A
public class ModuleA {
//耦合接口
ModuleB obj;
public ModuleA(ModuleB obj) {
this.obj = obj;
}
//A模块的方法要使用耦合模块功能
public void sb(){
obj.nb();
}
}
//测试代码
public class Test {
public static void main(String[] args) {
ModuleA moduleA1 = new ModuleA( new ModuleB1() );
ModuleA moduleA2 = new ModuleA( new ModuleB2() );
moduleA1.sb();
moduleA2.sb();
}
}
第十二节,常用类
内部类:
1.成员内部类
定义位置: 类的内部 方法外部
定义方式:
class Out{
*
class InClass{
*
}
}
内部类可定义成分: ① 实例变量 ②实例方法
可访问外部类成分: ① 实例变量 ②实例方法 ③静态属性 ④静态方法
*
如何使用: 1. 所在外部内使用: 实例化内部类对象 然后使用 InClass obj = new InClass()
- 其他位置单独使用: 创建外部类对象 然后创建内部类对象 Out.InClass obj = new Out().new InClass()
补充:如果是调用内部类的静态方法,则无需创建内部对象
*
*
- 静态内部类
- 定义位置: 类的内部 方法外部
定义方式:
class Out{
static class InClass{
}
}
内部类可定义成分: ① 实例变量 ②实例方法 ③静态属性 ④静态方法
可访问外部类成分: ① 静态属性 ②静态方法
*
如何使用: 1. 所在外部内使用: 实例化内部类对象 然后使用 InClass obj = new InClass()
- 其他位置单独使用: 实例化内部类对象 然后使用 Out.InClass obj = Out.InClass();
补充:如果是调用内部类的静态方法,则无需创建内部类对象
3.局部内部类
public class Foo {
int age =999;
int num ;
static int xx;
public void m1( int sb ){
int age = 99;
final int year=2020;
//局部(方法)内部类
class InClass{
private int age =9;
private void showAge(){
int age = 1;
System.out.println(this.age);
System.out.println(num);
System.out.println(xx);
}
public void showYear(){
System.out.println(year);
}
}
InClass obj = new InClass();
obj.showYear();
obj.showAge();
}
}
4.匿名内部类
public interface IFly {
public void fly();
}
public class TestNoneNameClass {
public static void main(String[] args) {
IFly obj3= new Bird();
obj3.fly();
IFly obj = new IFly(){
@Override
public void fly() {
System.out.println("火箭飞");
}
};
obj.fly();
IFly obj2 = new IFly(){
@Override
public void fly() {
System.out.println("大鹏飞......");
}
};
obj2.fly();
IFly iFly = new IFly() {
@Override
public void fly() {
System.out.println("hello......");
}
};
iFly.fly();
new IFly(){
@Override
public void fly() {
System.out.println("飞机飞......");
}
}.fly();
// lambda 表达式
IFly ff = ()->{ System.out.println("各种飞......"); };
ff.fly();
}
}
class Bird implements IFly{
@Override
public void fly() {
System.out.println("小鸟飞.....");
}
}