1、javase基础语法

Java基础

一、Java基础知识了解

1.JDK、JRE、JVM三者之间的关系
  • JDK:Java开发工具箱
  • JRE:java运行环境
  • JVM:java虚拟机

JVM是不能独立安装的。
JRE和JDK都是可以独立安装的。

安装JDK的时候:JRE就自动安装了,同时JRE内部的JVM也就自动安装了。
安装JRE的时候:JVM也就自动安装了。(比如部署项目,只需要安装JRE就行,JRE体积小)

2.对Java的加载与执行的理解

java程序非常重要的两个阶段:

  • 编译阶段:.java文件通过编译成.class文件,jvm才能识别
  • 运行阶段:jvm执行.class文件

.class不是二进制文件,无法直接在操作系统运行

动力节点java加载与执行.png

3.Java知识图解

JavaSE课程内容介绍.jpg

4.计算机中的加减法

原码

虽然原码表示简单,但是原码在做加减法的时候,很麻烦!以4bit位为例:

1+(-1) = 0001 + 1001 = 怎么让计算机去计算?(虽然我们知道该去怎么算,但是计算机不知道!)

我们得创造一种更好的表示方式!于是我们引入了反码:

反码
  • 正数的反码是其本身
  • 负数的反码是在其原码的基础上, 符号位不变,其余各个位取反

经过上面的定义,我们再来进行加减法:

1+(-1) = 0001 + 1110 = 1111 => -0 (直接相加,这样就简单多了!)

思考:1111代表-0,0000代表+0,在我们实数的范围内,0有正负之分吗?

  • 0既不是正数也不是负数,那么显然这样的表示依然不够合理!

补码

根据上面的问题,我们引入了最终的解决方案,那就是补码,定义如下:

  • 正数的补码就是其本身 (不变!)
  • 负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)

其实现在就已经能够想通了,-0其实已经被消除了!我们再来看上面的运算:

1+(-1) = 0001 + 1111 = (1)0000 => +0 (现在无论你怎么算,也不会有-0了!)

所以现在,4bit位能够表示的范围是:-8~+7(Java使用的就是补码!)

二、Java基础语法

1.注释

单行注释://

多行注释:/_   _/

文档注释:/**   */

待做标记(类似于书签)://TODO

2.Java关键字

Java的关键字一共有50个。

java关键字.png

Java的三个特殊值:true, false,null。

3.Java标识符

标识符:给变量、类等取名的字符序列。

标识符命名规则:

  • 只能有26个英文字母大小写,数字0-9,下划线_,美元符号$。
  • 不能以数字开头。
  • 不能包含空格。
  • 不能直接使用关键字、保留字、特殊值。
  • 严格区分大小写。

标识符命名规范:

  • 见名知意
  • 类名等:每一个单词的首字母大写,形式:XxxYyyZzz
  • 变量名等:从第二个单词开始首字母大写,形式:xxxYyyZzz
  • 常量名等:每一个字母都大写,单词之间可以使用下划线分割,形式:XXX_YYY_ZZZ
  • 包名:每一个单词都是小写,单词之间使用.分割,形式:xxx.yyy.zzz

4.Java数据类型分类

基本数据类型(8种):byte,short,int,long,float,double,char,boolean。

引用数据类型:类、接口、数组、枚举、注解等

数据类型分类.png

基本数据类型
数据类型关键字内存占用取值范围
整数byte1负的2的7次方 ~ 2的7次方-1(-128~127)
short2负的2的15次方 ~ 2的15次方-1(-32768~32767)
int4负的2的31次方 ~ 2的31次方-1
long8负的2的63次方 ~ 2的63次方-1
浮点数float41.401298e-45 ~ 3.402823e+38
double84.9000000e-324 ~ 1.797693e+308
字符char20-65535
布尔boolean1true,false

在java中整数默认是int类型,浮点数默认是double类型。

int a = 10;
int b = 010;//八进制0
int c = 0x10;//0x开头十六进制    0-9  A-F   
System.out.println(a);//10
System.out.println(b);//8
System.out.println(c);//16
//float   舍入误差
//double
float a = 2121233213412412f;
float b = a + 1;
System.out.println(a==b);//true
//最好完全避免使用浮点数进行比较
char a='a';
char b='中';
System.out.println(a);//a
System.out.println((int)a);//7
System.out.println(b);//中
System.out.println(((int)b));//20013
char c='\u0061';
System.out.println(c);//a
// \t  空格  
//\n  换行
System.out.println("hello\tworld");

变量
数据类型 变量名 = 初始化值; // 声明变量并赋值
String name="zhangsan";
System.out.println(name);
  • 定义和赋值两部分
  • 他在内存里开辟了一片空间,可以存数据
  • 他可以反复的到处使用
  • 变量其实就是一个引用,他指向堆内存的一块区域,我们想操作一个对象只需要使用它的引用即可

使用变量时的注意事项

  1. 在同一对花括号中,变量名不能重复。
  2. 变量在使用之前,必须初始化(赋值)。
  3. 定义long类型的变量时,需要在整数的后面加L(大小写均可,建议大写)。因为整数默认是int类型,整数太大可能超出int范围。
  4. 定义float类型的变量时,需要在小数的后面加F(大小写均可,建议大写)。因为浮点数的默认类型是double, double的取值范围是大于float的,类型不兼容。

类型转换

自动类型转换图1.jpg

整型里边小转大自动转,大转小需要强转,应为可能会丢失精度;

整型和浮点型:浮点型转整型需要强转,反之不需要,但是他以科学计数法表示可能会丢失精度;

char能不能和整型转: 就是两个字节,随便转,就能当成一个short。但是char类型的变量经过计算都是int。任何short,byte,int,char无论是逻辑运算还是数学运算结果都是int;

int a=10;
double b=11.5;
double c= a+b; //数据范围小的数值或者变量赋值给另一个表示数据范围大的变量,自动转
int d= (int) (a+b);//数据范围大的数值或者变量赋值给另一个表示数据范围小的变量,需强转

int a=128;
byte b= (byte) a;
System.out.println(b);//-128,内存溢出

5.运算符

5.1 逻辑运算符

位运算

位运算是将数据先转化为二进制数补码形式,再逐位(bit)按规则计算;

作用说明
&按位与a&b,a和b都是true,结果为true,否则为false
|按位或a|b,a和b都是false,结果为false,否则为true
~按位非0取反为1,1取反为0
^按位异或a^b,a和b结果不同为true,相同为false
//两个数转为二进制,然后从高位开始比较,如果相同则为0,不相同则为1。
int a=10;
int b=3;
int c=10;
System.out.println(a^b);//9
System.out.println(a^c);//0

逻辑运算符

逻辑运算又称布尔运算。常用0、1或者true、false来表示两者的关系;

符号作用
&&短路与
||短路或
!逻辑非

在逻辑与运算中,只要有一个表达式的值为false,那么结果就可以判定为false了,没有必要将所有表达式的值都计算出来,短路与操作就有这样的效果,可以提高效率。同理在逻辑或运算中,一旦发现值为true,右边的表达式将不再参与运算。

  • 逻辑与&,无论左边真假,右边都要执行。
  • 短路与&&,如果左边为真,右边执行;如果左边为假,右边不执行。
  • 逻辑或|,无论左边真假,右边都要执行。
  • 短路或||,如果左边为假,右边执行;如果左边为真,右边不执行。

5.2 算数运算符

加 减 乘 除 取余(%)

int a = 10;
int b = 20;
System.out.println("" + a + b);//1020  先转成string
System.out.println(a+b+"");//30

5.3 赋值运算符
  • ++:自增,变量的值加1
int x = 10;
int y = x++; // 赋值运算,++在后边,所以是使用x原来的值赋值给y,x本身自增1
System.out.println("x:" + x + ", y:" + y); // x:11,y:10
int m = 10;
int n = ++m; // 赋值运算,++在前边,所以是使用m自增后的值赋值给n,m本身自增1
System.out.println("m:" + m + ", m:" + m); // m:11,m:11
  • –:自减,变量的值减1
  • 赋值运算符的作用是将一个表达式的值赋给左边,左边必须是可修改的,不能是常量。
    | 符号 | 作用 | 说明 |
    | — | — | — |
    | = | 赋值 | a=10,将10赋值给变量a |
    | += | 加后赋值 | a+=b,a=a+b |
    | -= | 减后赋值 | a-=b,a=a-b |
    | = | 乘后赋值 | a=b,将a×b的值给a |
    | /= | 除后赋值 | a/=b,将a÷b的商给a |
    | %= | 取余后赋值 | a%=b,将a÷b的余数给a |

5.4 关系运算符
符号说明
==a==b,判断a和b的值是否相等,成立为true,不成立为false
!=a!=b,判断a和b的值是否不相等,成立为true,不成立为false
>a>b,判断a是否大于b,成立为true,不成立为false
>=a>=b,判断a是否大于等于b,成立为true,不成立为false
<a<b,判断a是否小于b,成立为true,不成立为false
<=a<=b,判断a是否小于等于b,成立为true,不成立为false

注意事项:

  • 关系运算符的结果都是boolean类型,要么是true,要么是false;
  • 千万不要把“”误写成“=”,"“是判断是否相等的关系,”="是赋值;

5.5 三元运算符
关系表达式 ? 表达式1 : 表达式2;

如果条件表达式成立或者满足则执行表达式1,否则执行第二个。

int a = 10;
int b = 20;
int c = a > b ? a : b; // 判断 a>b 是否为真,如果为真取a的值,如果为假,取b的值

6.流程控制语句

6.1 if语句(判断语句是就执行否就跳过)

if (i == 0) {}

if (i == 0) {} else {}

if (i == 0) {} else if (i == 1) {}

6.2 switch(case的后面不写break,将出现穿透现象)
//i可以是 byte short int String enum 的数据

Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
switch (i){
    case 1:
        System.out.println("111");
        break;
    case 2:
        System.out.println("222");
        break;
    default:
        System.out.println("333");
        break;
}
  • switch(表达式)的值的类型,只能是:4种基本数据类型(byte,short,int,char),两种引用数据类型(JDK1.5之后枚举、JDK1.7之后String)
  • case后面必须是常量值,而且不能重复

6.3 for

语法:

for (初始化语句;条件判断语句;条件控制语句) {
循环体语句;
}

for(int i=1; i<=5; i++) {
    System.out.println(i);
}

6.4 while
while (i<5){i++;}//先判断,符合条件循环一次
do {i++;}while (i<5);//先执行,在判断

6.5 break

跳出循环,结束循环;

for循环可已打标签,使用【break + 标签名】可以 退出 被打标签的循环;

flag:
for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 2; j++) {
        if (j > 0) {
            break flag;
        }
        System.out.println("====" + j);
    }
}

6.5 continue

跳过本次循环,继续下次循环;

7.数组

7.1 数组的定义
int[] nums = {1,2,3}; 
int[] nums = new int[3]; 
//类型[] 名字 = new 类型[长度];

数组中可以存储任意类型的数据,但是数组本身是引用类型的,创建数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是这块连续空间的首地址

7.2 数组的性质
  1. 数组一旦建立不能改变长度;
  2. 每个位置只能存一个值,多了会覆盖;
  3. 编号从0开始,下标;
  4. 他有个长度的属性,最后一个位置的编号是长度-1;
  5. 数组里边可以是基本类型,也可以是引用类型;

7.3 数组的遍历
for (int i = 0; i < nums.length; i++) {
    System.out.println(nums[i]);
}
//第二种增强for遍历
for (int i : nums) {
    System.out.println(i);
}

7.4 Arrays工具类
  • binarySearch(数组,key)-二分搜索
int[] arr = {2, 12, 6, 19, 8};
int index = Arrays.binarySearch(arr, 19);
System.out.println(index);//3;
  • Arrays.sort(数组);
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));//[2, 6, 8, 12, 19]
  • 数组的拷贝
int[] arr1 = Arrays.copyOf(arr, 3);
System.out.println(Arrays.toString(arr1));//[2, 6, 8]
  • 数组深拷贝和浅拷贝
int[] nums = {10, 15, 33};
System.out.println(nums.toString());
int[] num1 = nums;
//浅拷贝:拷贝的是内存地址
for (int i = 0; i < num1.length; i++) {
    System.out.println(num1.toString());
}
//深拷贝拷贝的是内容
int[] num2 = new int[nums.length];
for (int i = 0; i < num2.length; i++) {
    int num = nums[i];
    num2[i] = num;
    System.out.println(num2.toString());
}
  • 比较数组的内容
boolean equals = Arrays.equals(arr, arr1);
System.out.println(equals);//false

7.5 二维数组

类似于一个平面;

int[][] nums=new int[2][4];//[2]表示分2个一维数组,[4]表示从每个一维数组再分4个数字
nums[1][2]=2;
nums[2][4]=11;

8.方法

格式:

public static 返回值类型 方法名(参数) {
    方法体; 
    return 数据 ;
}
名词解释
返回值类型方法操作完毕之后返回的数据的数据类型;如果方法操作完毕,没有数据返回,这里写void,而且方法体中一般不写return;
方法名调用方法时候使用的标识;
参数由数据类型和变量名组成,多个参数之间用逗号隔开;
方法体完成功能的代码块;
return如果方法操作完毕,有数据返回,用于把数据返回给调用者;

三、面向对象

1、类的定义
① 定义类

② 编写类的成员变量

③ 编写类的成员方法
public class Student {
    // 属性 : 姓名, 年龄
    // 成员变量: 跟之前定义变量的格式一样, 只不过位置发生了改变, 类中方法外
    String name;
    int age;

    // 行为 : 学习
    // 成员方法: 跟之前定义方法的格式一样, 只不过去掉了static关键字.
    public void study(){
        System.out.println("学习");
    }
}
  • 创建对象的格式:类名 对象名 = new 类名();
  • 调用成员的格式:对象名.成员变量;对象名.成员方法();

2、成员变量和局部变量的区别
  • 成员变量(类中方法外)局部变量(方法内部或方法声明上)
  • 成员变量(堆内存)局部变量(栈内存)
  • 成员变量(随着对象的存在而存在,随着对象的消失而消失)局部变量(随着方法的调用而存在,随着方法的调用完毕而消失)
  • 成员变量(有默认初始化值)局部变量(没有默认初始化值,必须先定义,赋值才能使用)

3、构造方法
  • 方法名与类名相同,大小写也要一致
  • 没有返回值类型,连void都没有
  • 没有具体的返回值(不能由retrun带回结果数据)
  • 不能手动调用构造方法
  • 创建对象的时候调用,每创建一次对象,就会执行一次构造方法

**构造方法的作用:**用于给对象的数据(属性)进行初始化

**构造方法的创建:**如果没有定义构造方法,系统将给出一个默认的无参数构造方法如果定义了构造方法,系统将不再提供默认的构造方法

4、方法的重载

方法重载的概念:方法重载指同一个类中定义多个方法之间的关系,满足下列条件的多个方法相互构成重载

  • 多个方法在同一个类中
  • 多个方法具有相同的方法名
  • 多个方法的参数不相同,类型不同或者数量不同

注意:

  • 重载仅对对应方法的定义,与方法的调用无关,调用方式参照标准格式
  • 重载仅针对同一个类中方法的名称与参数进行识别,与返回值无关,换句话说不能通过返回值来判定两个方法是否相互构成重载
public class Study {
    public int studyTime;
    //重载构造
    public Study(){
    }
    public Study(int studyTime) {
        this.studyTime = studyTime;
    }
    //重载方法
    public  void  StudyTime(){
    }
    public  void  StudyTime(String studyTime){
    }
}

5、封装

将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问
成员变量private,提供对应的getXxx()/setXxx()方法

好处:通过方法来控制成员变量的操作,提高了代码的安全性
把代码用方法进行封装,提高了代码的复用性

5.1 权限修饰符

被private修饰的成员,只能在本类进行访问,针对private修饰的成员变量,如果需要被其他类使用, 提供相应的操作提供“get变量名()”方法,用于获取成员变量的值,方法用public修饰提供“set变量名(参数)”方法,用于设置成员变量的值,方法用public修饰

权限修饰符访问范围

访问权限修饰符.png

5.2 this关键字

this修饰的变量用于指代成员变量,其主要作用是(区分局部变量和成员变量的重名问题)

  • 方法的形参如果与成员变量同名,不带this修饰的变量指的是形参,而不是成员变量
  • 方法的形参没有与成员变量同名,不带this修饰的变量指的是成员变量

6、继承

可以使得子类具有父类的属性和方法,还可以在子类中重新定义,以及追加属性和方法

**实现继承的格式:**继承通过extends实现

格式:class 子类 extends 父类 { } ;举例:class Dog extends Animal { }

继承可以让类与类之间产生关系,子父类关系,产生子父类后,子类则可以使用父类中非私有的成员。

6.1 继承特点
  • Java中类只支持单继承,不支持多继承
  • Java中类支持多层继承

6.2 方法重写

发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为 private 则子类就不能重写该方法。

6.3 抽象类

1. 抽象方法定义
权限修饰符 abstract 返回值类型 方法名字(参数列表) ;
abstract关键字
抽象方法没有方法体, 不需要{},直接分号结束

当一个类中的方法是抽象方法的时候,这个类必须是抽象类,在类的关键字class前面使用abstract修饰.

public abstract class Animal {
    /**
     * 动物吃什么?
     * 说不清楚,抽象,可以不说
     */
    public abstract void eat();
}

2.抽象类的使用方式
  • 抽象类不能实例化对象,不能new对象(为什么不能建立对象,类中有没有主体的方法存在,建立对象调用抽象方法是绝对的错误,因此不能建立对象)
  • 需要子类继承抽象类,重写抽象方法
  • 创建子类对象
  • 使用多态性创建对象,调用方法执行子类的重写
public class Cat extends Animal{
    /**
     * 重写父类的方法
     * 去掉修饰符 abstract
     * 添加主体 {}
     */
    public  void eat(){
        System.out.println("猫吃鱼");
    }
}
public static void main(String[] args) {
    //创建Animal的子类对象
    Animal animal = new Cat();
    //eat方法不可能执行父类,运行子类的重写
    animal.eat();
}

3.抽象类中成员的定义

①抽象类中能否定义成员变量

可以定义成员变量,成员变量私有修饰,提供方法 get/set,由子类的对象使用

public abstract class Animal {
    //抽象类中能否定义成员变量
    private String name;
    public abstract void eat();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public static void main(String[] args) {
    Animal animal = new Cat();
    animal.eat();
    //animal对象调用方法 get/ set
    animal.setName("tom");
    String name = animal.getName();
    System.out.println(name);
}

②抽象类中有构造方法吗

抽象类中有构造方法,不写有默认的

public abstract class Animal {

    public Animal(){
        System.out.println("Animal的构造方法");
    }

    public Animal(String name){
        this.name = name;
        System.out.println("有参数String的构造方法");
    }

    //抽象类中能否定义成员变量
    private String name;
    public abstract void eat();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class Cat extends Animal {

    public Cat(){
        //调用父类的有参数构造方法
        super("张三");
    }

    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

③抽象中能否不定义抽象方法

抽象类中,可以不定义出抽象方法.

但是,如果有抽象方法存在,这个类必须是抽象类

④子类还是抽象类的问题

当一个子类继承一个抽象类的时候,子类必须重写全部的抽象方法.假如子类重写了部分抽象方法,这个子类依然还是抽象类.

public abstract class Animal {
    public abstract void eat();
    public abstract void sleep();
}
/**
 * Cat继承父类Animal,Cat类拥有了父类的成员
 * 父类有什么,我就有什么
 */
public abstract class Cat extends Animal {
    public  void eat(){}
    /**
     * 方法sleep没有重写
     * 还是一个抽象的方法
     */
    //    public abstract void sleep();
}

6.4 接口

当一个抽象类中的所有方法全部是抽象的时候,可以将这个抽象类换一个更加贴切的名词,叫他接口. 接口是特殊的抽象类.

接口在编译后,依然还是.class文件

语法:public interface 接口名{}

1.接口中成员定义
  • 成员变量
    • 成员变量的定义是具有固定格式
    • 成员变量的修饰符是固定 public static final
public static final 数据类型  变量名 =;
  • 成员方法
    • 成员方法的定义是具有固定格式
    • 成员方法的修饰符固定为 public abstract
public abstract 返回值类型 方法名(参数列表) ;

2.接口的使用方式
  • 接口不能建立对象,不能new
  • 需要定义类,实现接口(继承类,在接口中称为实现,理解为继承)
    • 实现接口,使用新的关键字 implements
    • 实现的格式 class 类 implements 接口名{}
  • 重写接口中的抽象方法
  • 创建子类的对象
/**
 *  定义好的接口
 */
public interface MyInterFace {
    //接口的成员变量
    public static final int A = 1;
    //接口的成员方法
    public abstract void myInter();
}
/**
 *  定义MyInterFace接口的实现类
 *  重写接口的抽象方法
 */
public class MyInterFaceImpl implements MyInterFace{
   public void myInter(){
       System.out.println("实现类实现接口,重写方法");
    }
}
public static void main(String[] args) {
    //创建对象,多态性,创建接口实现类的对象
    MyInterFace my = new MyInterFaceImpl();
    my.myInter();
    //输出接口中的成员A的值
    System.out.println(my.A);
}

3.接口的多实现

类和类之间单继承,局限性的问题.接口的出现,是对单继承的改良,允许一个类同时实现多个接口.

语法:class 类名 implements 接口A,接口B{}

实现类,重写实现的多有接口中的抽象方法

public interface A {
    public abstract void a();
}
public interface B {
    public abstract void b();
}
/**
 *  实现接口A和B
 */
public class C implements A,B{
    @Override
    public void a() {
        System.out.println("重写A接口方法");
    }

    @Override
    public void b() {
        System.out.println("重写B接口方法");
    }
}
public static void main(String[] args) {
    C c = new C();
    c.a();
    c.b();
}

**注意:一个类实现多个接口,多个接口不能有同名的方法,编译无法识别 **

实现类实现接口,重写一部分抽象方法,实现类还是一个抽象类

public interface A {
    public abstract void a1();
    public abstract void a2();
}
public abstract class B implements A {
    public  void a1(){

    }
   // public abstract void a2();
}

6.5 super

子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用 super 关键字,修饰 父类成员变量,类似于之前学过的 this 。

6.6 final
  • fianl修饰类:该类不能被继承(不能有子类,但是可以有父类)
  • final修饰方法:该方法不能被重写
  • final修饰变量:表明该变量是一个常量,不能再次赋值
    • 变量是基本类型,不能改变的是值
    • 变量是引用类型,不能改变的是地址值,但地址里面的内容是可以改变的

7、多态

7.1 对象的多态性

同一个对象,在不同时刻表现出来的不同形态

多态的前提:

  • 要有继承或实现关系
  • 要有方法的重写
  • 要有父类引用指向子类对象
父类 变量(对象名)  =  new 子类对象(); //多态写法
public class Person {
    String s = "父类成员";

    public void eat(){
        System.out.println("人在吃饭");
    }
}
public class Student extends Person {
    String s = "子类成员";

    public void eat(){
        System.out.println("学生吃饭");
    }
}
public static void main(String[] args) {
    Person p = new Student();
    //对象p,子类对象,调用成员变量s
    System.out.println(p.s);
    //子类对象调用方法
    p.eat();//父类成员 学生吃饭
}

结论 : 成员方法编译看左边,运行看右边.成员变量都是左边

7.2 多态的转型

多态的程序中,不能调用子类的特有成员!!

只能调用子类父类的共有成员

class Animal {
    public void eat(){
        System.out.println("动物吃饭");
    }
}

class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
     public void catchMouse() {
        System.out.println("捉老鼠");
    }
}

public class Test1Polymorphic {
    /*
        多态的前提:

            1. 要有(继承 \ 实现)关系
            2. 要有方法重写
            3. 要有父类引用, 指向子类对象
     */
public static void main(String[] args) {
    //创建对象,多态性
    //父类 = new 任意子类对象() 扩展
    Animal animal = new Cat();
    animal.eat();
    //Cat类的特有功能 catchMouse()方法
    //类型转换,强制
    //Cat提升为了Animal,转回Cat类型
    Cat c = (Cat)animal;
    c.catchMouse();
}
}

多态的好处和弊端

  • 好处

提高程序的扩展性。定义方法时候,使用父类型作为参数,在使用的时候,使用具体的子类型参与操作

  • 弊端

不能使用子类的特有成员

多态中的转型

  • 向上转型
    • 父类引用指向子类对象就是向上转型
  • 向下转向(强转)
    • 子类型 对象名 = (子类型)父类引用;

7.3 多态中的转型异常

异常ClassCastException 类型转换异常,在多态中经常发生.

是在进行类型的强制转换的时候发生,我们现在的案例是Dog不能转成Cat.

需要解决这个异常 :  对象是Cat转Cat,是Dog换Dog

运算符 : 比较运算符,结果是boolean类型

运算符是关键字 instanceof

instanceof的语法格式:

对象名 instanceof  类的名字
解析: 比较这个对象,是不是由这个类产生的
c instanceof Cat  解释: c对象是不是Cat类产生的,如果是结果就是true

8、static 关键字

static修饰符 : 最早出现在main方法中.只能修饰成员,不能写在方法的内部,被static修饰的成员,静态成员变量和静态的成员方法

8.1 静态修饰成员变量

static 修饰的成员变量,是被所有的对象共享的数据.没有被static修饰的成员变量,是每个对象的独享数据或者是特有数据

static修饰的特点

  • 被类的所有对象共享是我们判断是否使用静态关键字的条件
  • 随着类的加载而加载,优先于对象存在
    对象需要类被加载后,才能创建
  • 可以通过类名调用
    也可以通过对象名调用
  • 静态成员跟随自己的类进入到元数据区(静态区域)
  • 静态成员属于自己的类,不属于对象
  • 静态成员进入内存后,赋默认值
  • 静态成员变量的初始化实际早于对象

static关键字注意事项

  • 静态方法只能访问静态的成员
  • 非静态方法可以访问静态的成员,也可以访问非静态的成员
  • 静态方法中是没有this关键字

8.2 静态代码块

写在类中方法外面 : static{}

静态代码块的执行时机 : 只要使用了这个类的成员(new对象,调用静态方法,静态变量),静态代码块就会执行,而且就一次

后面的课程会自己写静态代码块 : 数据库连接池 (C3P0,Druid)

JDBC注册数据库驱动程序,使用代码块

9. 内部类

所谓内部类,就是在一个类的内部,定义了另外的一个类

class A{ //外部类,封闭类
    class B{} //内部类,嵌套类
}

9.1 成员内部类

成员内部类,是一个类定义在了另一个类的成员位置.这个内部类可以使用成员修饰符,public .static. final .private

对于内部来说 : 可以直接使用外部类的成员,如果外部类要使用内部类的成员,必须要创建对象.

语法: 外部类名.内部类名 = new 外部类对象().new 内部类对象()
//外部类
public class Outer {

    public void outer(){
        System.out.println("外部类的方法outer");
    }

    //内部类
    public class Inner{
        public void inner(){
            System.out.println("内部类的方法inner");
        }
    }
}
public static void main(String[] args) {
    //调用内部类的方法inner()
    Outer.Inner oi = new Outer().new Inner();
    oi.inner();
}
  • 内部类Inner,编译后有class文件吗?有class文件,名字是外部类$内部类
  • 内部类也是类,继承Object,可以实现接口
内部类是静态的调用方式 : 外部类名.内部类名 变量名 = new 外部类.内部类()

9.2 局部内部类

局部内部类 : 要定义在方法里面. 方法里面是局部位置,不能使用成员修饰符,权限,静态不能用

class A{
    public void a(){
        class B{} //局部内部类
    }
}
public class Outer {
    /**
     *  Inner类,是方法Outer的局部
     *  依然方法,才能被外界访问
     */
    public void outer(){
        final int x=1class Inner{
            public void inner(){
                System.out.println("局部内部类的方法!!"+x);
            }
        }
        //方法,建立对象
        Inner inner = new Inner();
        inner.inner();
    }
}
public static void main(String[] args) {
    //调用内部类的方法inner()
    //直接调用,不能调用
    Outer outer = new Outer();
    outer.outer();
}

局部内部类,访问局部变量,变量必须final修饰

9.3  匿名内部类

匿名内部类,就是没有名字的内部类,只能写在方法中,为了简化代码书写.

  • 匿名内部类使用的前提 :
    • 必须有接口实现,或者是类的继承
    • 格式 :
new 接口或者父类(){
    //重写抽象方法
};
格式 == 实现类,实现接口,重写方法,创建对象
public interface MyInter {
    public abstract void inter();
    public abstract void inter2();
}
public class InnerClassTest {
    public static void main(String[] args) {
        //匿名内部类,简化书写,不写实现类
        //同时调用多个重写方法
        /*
         *  new MyInter(){}; 是接口实现类的匿名对象
         * 多态 : 接口 变量 = 实现类对象
         */
       MyInter my =  new MyInter(){

            @Override
            public void inter() {
                System.out.println("实现类实现接口重写方法");
            }

            @Override
            public void inter2() {
                System.out.println("实现类实现接口重写方法2222");
            }
        };
       my.inter();
       my.inter2();
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值