一.多态
1 .多态的概念:多态是一个事物在不同时刻体现出来的不同状态。例如:水有三种状态:固态、气态、液态。
2.多态的三个前提条件:
(1)必须有继承关系(没有继承关系的话,谈不上多态)
(2)必须有方法重写(子类出现了父类一样的方法声明)
(3)父类引用指向子类对象:向上转型。例如:Fu f=new Zi();
这三个条件缺一不可!
3.多态的成员访问特点:
成员变量:编译看左,运行看左。
非静态成员方法:编译看左,运行看右。由于存在方法重写,所以就运行最终的是子类的成员方法。
静态成员方法:编译看左,运行看左。
构造方法:还是对象进行初始化,由于是一种继承方法,还是分层初始化。
成员访问的例子:
class Fu{
public int num = 10 ;
//父类的成员方法
public void show(){
System.out.println("show Fu...");
}
//静态方法
public static void function(){
System.out.println("function Fu....");
}
}
//子类
class Zi extends Fu{
int num = 20 ;
public void show(){
System.out.println("show Zi...");
}
public static void function(){
System.out.println("function Zi....");
}
}
//测试类
public class DuoTaiDemo {
public static void main(String[] args) {
//创建父类的对象:多态的形式
// 有父类引用指向子类对象:向上转型
Fu f = new Zi() ;
//访问成变量:编译看左,运行看左
System.out.println(f.num);//10
//调用成员方法:show() 编译看左,运行看右
f.show() ;//show Zi...
//静态方法编译看做,运行看左
f.function() ;//function Fu....
}
}
4.多态的优点:
(1)可以提高代码的维护性(由继承保证)
(2)可以提高代码的扩展性(由多态保证)
5.多态的弊端:不能访问子类的特有功能。
解决方法:(1)创建子类的具体对象,来访问自己的特有功能。虽然可以解决多态弊端,但是从内存角度考虑,
要创建子类对象,那么必须在堆内存开辟空间,浪费空间。
创建子类的具体对象时可能出现的异常:OOM异常;Out Of Memory严重异常:内存溢出。
(2)多态的第三个前提条件是,父类引用指向子类对象,那么,可不可以将子类的引用指向父类的
对象呢?答案是可以的。向下转型就是将父类的引用强制转换为子类的引用,前提是必须有父
类的引用存在。向下转型必须依赖于向上转型。
向下转型可能出现的异常:Class Cast Exception 类转换异常
ArrayIndexOutOfBoundsException 数组角标越界异常
Null Pointer Exception:空指针异常(解决方案:给对象做非空判断)
if(对象名!=null){
给对象进行操作
}
访问子类特有功能的例子:
package example;
class Animal2{
public void show(){
System.out.println("show Animal2...");
}
}
//子类
class Cat2 extends Animal2{
public void show(){
System.out.println("show Cat2....");
}
//特有功能
public void playGame(){
System.out.println("猫玩毛线...");
}
}
//测试类
public class DuoTaiDemo3 {
public static void main(String[] args) {
//多态的形式:父类引用指向子类对象
Animal2 a = new Cat2() ;
a.show() ;
Cat2 b=(Cat2)a;
b.playGame();
// a.playGame() ;
}
}
二.抽象类
1.概念:每一个动物的吃和睡的功能不一样,不应该把动物类定义为一个具体类,而是给出一个声明。
当一个类中如果有抽象功能(抽象方法)的时候,那么这个类一定要定义为抽象类。
2.抽象方法:没有方法体的一个方法。例如:public abstract void eat();
问题:一个抽象类中可以有非抽象方法吗:
答案:一个抽象类中可以有抽象方法,也可以有非抽象方法。
3.抽象类的实例化:
抽象类不能实例化,抽象类不能创建对象
一个抽象类如何进行实例化:通过抽象类多态形式:父类的引用指向子类对象,通过子类进行初始化。
抽象类实例化的例子:
abstract class Animal{
//抽象方法:没有方法体的一个方法
public abstract void eat() ;
public abstract void sleep() ;
//具体方法
/*public void eat(){
System.out.println("eat");
}*/
public void show(){
System.out.println("show Animal....");
}
}
//抽象的子类
//abstract class Cat extends Animal{
//
//}
//子类是具体类
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void sleep() {
System.out.println("猫趴着睡觉..");
}
}
//测试类
public class AbstractDemo {
public static void main(String[] args) {
//当前Animal已经被abstract修饰了
// Animal a = new Animal();//Cannot instantiate the type Animal:抽象类不能实例化:instaceof
//多态:父类引用指向子类对象
Animal a = new Cat() ; //Animal是抽象类,---->抽象类多态形式
a.eat() ;
a.sleep() ;
}
}
4.抽象类子类的特点:
如果抽象类的子类也是抽象类,那么这个子类就没有意义。
因为抽象类最终使用的就是通过子类进行对象的初始化,如果子类被抽象修饰了,那么也不能创建对象,
没有意义。
5.抽象类的成员特点
成员变量:可以是变量,也可以是自定义常量。
构造方法:抽象类可以有构造方法:包括有参构造和无参构造。
构造方法的作用:通过抽象类多态的形式,让子类进行数据初始化
成员方法:可以有抽象方法,也可以有非抽象方法。
6.抽象类的成员方法特性:
抽象方法:强制子类必须做一件事情:方法重写;
非抽象方法:由继承保证可以提高代码的复用性。
问题:一个类中如果没有抽象方法,那么这个类可不可以定义为一个抽象类呢?
答案:可以。定义为抽象类,不能让其创建对象。
例子:
abstract class Fu{
private String name ;
private int age ;
//成员变量
public int num = 100 ;
public final int num2 = 200 ; //被final修饰:自定义常量
//无参构造
public Fu(){
}
//有参构造
public Fu(String name,int age){
this.name = name ;
this.age = age ;
}
//抽象方法
public abstract void show();
//非抽象方法
public void function(){
System.out.println("function Fu...");
}
}
//子类
class Zi extends Fu{
@Override
public void show(){
System.out.println("show Zi....");
}
}
//测试类
public class AbstractDemo2 {
public static void main(String[] args) {
//抽象类多态:
//抽象类的类名 对象名= new 子类名() ;
Fu f = new Zi() ;
f.show() ;
f.function() ;
}
}
三.接口
1.概念:接口体现的是一种扩展功能。比如:猫可以跳高(并不是所有的猫都可以)
interface 接口名{
}
问题:接口里面的方法可以是非抽象方法吗?
答案:不可以,只能是抽象方法。
2.接口的特点:
(1)不能实例化(不能直接创建对象)
(2)接口中不能有构造方法
3.接口如何实例化:
(1)接口的子实现类:
a.接口的子实现类是抽象类,没有意义。实际开发中用的就是
b.接口的子实现类是非抽象类
(2)接口的实例化:就是通过子实现类对数据进行初始化
格式: class 子实现类名 implements(实现) 接口名{
}
4.接口成员的特点:
(1)成员变量:只能是常量,存在默认修饰符:public static final.
(2)构造方法:接口没有构造方法的。
(3)成员方法:接口中的成员方法默认修饰符 public abstract.
接口的例子1:
//定义跳高的接口
interface Jump{
//非抽象方法:抽象类中不能有抽象方法
// public void jump(){
// System.out.println("猫可以跳高了...");
// }
public abstract void jump() ;
//构造方法:不能有
// public Jump(){
//
// }
}
//子实现类是抽象类类
//abstract class Cat implements Jump{
//子实现类是非抽象类
class Cat implements Jump{
@Override
public void jump() {
System.out.println("猫可以跳高了...");
}
}
//测试类
public class InterfaceDemo {
public static void main(String[] args) {
//创建接口对象
// Jump j = new Jump() ;//接口不能实例化
//接口多态:接口的引用指向子实现类对象
Jump j = new Cat() ;
j.jump();
}
}
接口的例子2:
//定义一个接口
interface Inter{
public static final int num = 100 ;
public static final int num2 = 200 ;
//抽象方法
//全部给出默认修饰符
public abstract void show() ;
//接口没有构造方法
// public Inter(){
//
// }
public abstract void function() ;
}
//定义接口的子实现类:见名知意:接口名+impl
class InterImpl implements Inter{
@Override
public void show() {
System.out.println(num);
System.out.println(num2);
}
@Override
public void function() {
System.out.println("function InterImpl...");
}
}
//测试类
public class InterfaceDemo2 {
public static void main(String[] args) {
//创建接口对象:接口多态的形式
Inter i = new InterImpl() ;
// i.num = 20 ;//当前num变量:被final修饰
System.out.println(Inter.num);//接口名.成员变量(当前变量被static修饰)100
System.out.println(Inter.num2);//200
System.out.println("-------------");
i.show() ;//100
i.function() ;//200
}
}
面试题:接口和抽象类的区别
(1)成员的区别:
a.成员变量:
抽象类:成员变量可以是常量,也可以是变量;
接口:成员变量只能是一种常量,存在默认修饰符: public static final;
b.构造方法:
抽象类:可以有无参、有参构造方法
作用:通过子类进行数据初始化
接口:无构造方法
c.成员方法:
抽象类:可以有抽象方法,也可以有非抽象方法。
接口:只能有抽象方法,存在默认修饰符:public abstract;
(2)关系的区别:
a.类与类的关系:继承关系extends。java中只支持单继承,不支持多继承,可以实现多层继承。
b.类与接口的关系:实现关系implements。并且,一个类继承另一个类的同时,可以实现多个接口。
例如:class 子实现类名 extends Object implements 接口名1,接口名2{
}
c.接口与接口的关系:继承关系extend。可以支持单继承,也可以支持多继承。
(3)设计理念的区别
抽象类:体现的是一种“is a”的关系,存在继承关系。
接口:体现的是一种“like a”的关系,由于接口的扩展功能。
作业:
1:教练和运动员案例(学生分析然后讲解)
乒乓球运动员和篮球运动员。
乒乓球教练和篮球教练。
为了出国交流,跟乒乓球相关的人员都需要学习英语。
请用所学知识:
分析,这个案例中有哪些抽象类,哪些接口,哪些具体类
抽象类有:运动员类、教练类、人类
接口: 学习英语
具体类:乒乓球运动员类、篮球运动员类、乒乓球教练类、篮球教练类
2:final关键字可以干什么?有什么特点?
final可以修饰类,修饰成员方法和变量。
final修饰类,该类不能继承;
final修饰成员方法,该方法不能被重写;
final修饰变量,例如:final int x=10;该变量是一个常量(自定义常量);
final修饰局部变量:
(1)基本数据类型:如果局部变量是一个基本数据类型,那么被final修饰,基本数据类型的变量的值不能再改变;
(2)引用数据类型:如果用final修饰的引用类型的变量,那么它不能再重写分配堆内存空间,但是可以改变成员变量的值。
3:final关键字的面试题?
A:修饰局部变量
final修饰局部变量:
(1)基本数据类型:如果局部变量是一个基本数据类型,那么被final修饰,基本数据类型的变量的值不能再改变;
(2)引用数据类型:如果用final修饰的引用类型的变量,那么它不能再重写分配堆内存空间,但是可以改变成员变量的值。
B:初始化时机
在对象创建之前都可以进行初始化
(1)构造代码块中可以进行初始化;
(2)构造方法中可以进行初始化;
(3)定义成员变量的时候,可以直接进行初始化。
4:多态是什么,前提是什么?
多态是指一个事物在不同时刻体现出来的不同状态。
多态的前提:
(1)必须有继承关系
(2)必须有方法重写
(3)有父类引用指向子类对象(向上转型)
5:多态中成员访问的特点?
成员变量:编译看左,执行看左
成员方法:编译看左,运行看右,由于存在方法重写,所以运行最终的是子类的成员方法。
静态方法:编译看左,运行看左
6:多态的好处及弊端?如何解决多态的弊端?
多态的好处:
(1)可以提高代码的维护性(由继承保证)
(2)可以提高代码的扩展性(由多态保证)
多态的弊端:不能访问子类的特有功能
解决弊端方法:
(1)创建子类的具体对象,来访问自己的特有功能,虽然可以解决多态弊端,但是从内存角度考虑。
要创建子类对象,必须在堆内存开辟空间,浪费空间。
(2)既然多态的第三个前提条件:父类引用指向子类对象,那么我们也可以将子类的引用指向父类的对象,
即将父类的引用强制转换为子类的引用,前提是必须有父类的引用存在。
7:什么是向上转型?什么是向下转型?
向上转型:父类引用指向子类对象
向下转型:将父类的引用强制转换为子类的引用
8:抽象类概述及其特点?
抽象类的概述:当一个类中如果有抽象方法的时候,那么这个类就应该定义为一个抽象类。
抽象类的特点:抽象类不能实例化
9:抽象类成员特点?
成员变量:可以是变量,也可以是自定义常量
构造方法:抽象类可以有构造方法:包括有参构造和无参构造。
作用:通过抽象类多态的形式,让子类进行数据初始化
成员方法:可以有抽象方法,也可以有非抽象方法。
10:抽象类的小问题
A:一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
可以。意义:不能让其创建对象。
B:abstract不能和哪些关键字共存
abstract不能和private、final、static共同使用
11:接口的概述及其特点?
接口的概述:接口体现的是一种扩展功能。如:猫可以跳高(并不是所有的猫都可以)
接口的特点:不能实例化(不能直接创建对象)
12:接口的成员特点?
成员变量:只能是常量,存在默认修饰符:public static final
构造方法:接口是,没有构造方法的。
成员方法:接口中的成员方法默认修饰符public abstract
13:抽象类和接口的区别?
成员的区别:
(1)成员变量:
抽象类:成员变量可以是常量,也可以是变量。
接口:成员变量只能是一种常量:存在默认修饰符:public static final
(2)构造方法:
抽象类:可以有无参、有参构造方法
接口:没有构造方法
(3)成员方法:
抽象类:可以有抽象方法,也可以有非抽象方法
接口:只能是抽象方法,存在默认修饰:public abstract
关系的区别:
(1)类与类的关系:继承关系extends
(2)类与接口的关系:实现关系implements,并且一个类继承另一个类的同时,可以实现多个接口
(3)接口与接口的关系:继承关系,可以支持单继承,也可以支持多继承
day09
一.形式参数和返回值问题
1.形式参数:
(1)基本数据类型:你要什么数据类型,在实际传参的时候就传什么数据类型。形式参数的改变
对实际参数没有影响。
(2)引用数据类型:需要创建该类的对象
a.具体类:如果形式参数是一个具体类,那么需要创建该类对象。
b.抽象类:如果形式参数是一个抽象类,需要自定义一个子类,来进行实例化。
c.接口:如果形式参数是一个接口,需要定义一个接口的子实现类,通过接口多态的形式给接口实例化。
形式参数是抽象类的例子:
//声明一个抽象类
abstract class Person{
public abstract void study() ;
}
//定义一个PersonDemo类
class PersonDemo{
//成员方法
public void method(Person p){//Person p = new Perosn();//错误的:抽象类不能实例化---->抽象类的多态:Person p = new Student2() ;
p.study() ;
}
}
//自定义一个抽象的子类来进行Person的实例化
class Student2 extends Person{
@Override
public void study() {
System.out.println("good good study ,day day up!");
}
}
//测试类
public class PersonTest {
public static void main(String[] args) {
//需求:调用PersonDemo类中method()方法
//创建PersonDemo类的对象
// PersonDemo pd = new PersonDemo() ;
pd.method(p) ;
// //需要使用抽象类多态来实例化
// Person p = new Student2() ;
// pd.method(p) ;
//链式编程:
new PersonDemo().method(new Student2()) ;
}
}
2.返回值:
a.具体类:直接返回该类对象(通常实际开发中使用的是匿名对象)
b.抽象类:返回值如果是抽象类,需要返回的是该抽象类的子类对象。
c.接口:返回值如果是接口类型,需要返回的是该接口的子类实现对象。
二.内部类
1.定义:在一个类中定义另一个类,那么把这种情况称为内部类。
举例:在A中定义一个类B,类B就是类A的内部类,同理,类A就是类B的外部类。
内部类可以直接访问外部类的成员,包括私有。
外部类想要访问内部类的成员,必须通过创建内部类的对象访问。
内部类例子:
class Outer7 {
public int num = 10;
class Inner7 {
public int num = 20;
public void show() {
int num = 30;
System.out.println(num);
System.out.println(this.num);
System.out.println(new Outer7().num);//要访问外部类的成员变量:匿名对象 :
// new 外部类名().成员变量
//外部类的this限定
System.out.println(Outer7.this.num);
}
}
}
public class InnerClassTest {
public static void main(String[] args) {
Outer7.Inner7 oi = new Outer7().new Inner7();
oi.show();
}
}
2.内部类的分类:
成员内部类:在外部类的成员位置。
局部内部类:在外部类的局部位置定义的这个类。
3.成员内部类:
a. 在测试类中,调用成员内部类的方法:
外部类名.内部类名 对象名=外部类对象.内部类对象
b.成员内部类的修饰符:
private:为了保证数据的安全性
static:为了方便调用
如果成员内部类static修饰,那么要访问外部类的成员变量,这个变量必须被static修饰。
静态的成员内部类访问该类中的成员方法的格式:
外部类名.内部类名 对象名=new 外部类名.内部类名().
结论:对于静态的成员内部类来说,无论静态成员内部类中的成员方法是静态的还是非静态的,要访
问外部类的成员变量,该变量必须被static修饰。
4.局部内部类:定义在外部类的局部位置
结论:无论是局部内部类还是非静态的成员内部类 ,都可以直接访问外部类的成员,包括私有。
例子:
//外部类
class Outer3{
//定义外部类的变量
public int num = 10 ;
//成员内部类(非静态成员内部类)
class Inner3{
//内部类的成员方法(非静态的成员方法)
public void show(){
System.out.println(num);
}
}
/*public void method(){
Inner3 i = new Inner3() ;
i.show() ;
}*/
}
//测试类
public class InnerDemo3 {
public static void main(String[] args) {
/**
* 需求:现在需要访问Inner3成员内部类中的show()方法
* */
// Inner3 i = new Inner3() ; //Inner3是一个成员内部类
// 外部类名.内部类名 对象名 = 外部类对象.内部类对象;
Outer3.Inner3 oi = new Outer3().new Inner3() ;
//使用对象名调用show()方法
oi.show() ;
}
}
面试题:局部内部类访问局部变量为什么会出现问题?
当前局部变量报错,必须用final修饰,为什么要用final修饰?
因为局部变量时随着方法调用而生成的,随着方法的调用完毕而消失,而现在局部位置有一个局
部内部类,它要在自己的成员方法位置访问当前的局部变量,必须把变量变成一个常量,要用final,
这样的一个值永远是固定的。
5.匿名内部类:是内部类的简化版格式
(1) 前提条件:必须存在一个接口或者是一个类(可以是具体类,也可以是一个抽象类)
(2)书写格式: new 接口名或者类名(){
方法重写;
}
(3)匿名内部类的实质:继承了该类(抽象类)或者是实现了该接口的子类对象。
6.如何使用API
(1)打开API:
显示---->输入你查找的类
索引---->搜索
(2)找到某一个类:
对该类的描述
看类结构:
看该类是否有字段(变量),构造方法(如何创建该类对象),方法(类的成员方法)
出现该类的版本号:
Scanner java.util.Scanner;
JDK5.0以后的新特性:自动拆装箱(int--->Integer,char--->Character),静态导入(导入的方法级别),可变参数,增强 for循环(集合),枚举
JDK7.0也有新特性(匿名内部类:局部内部类访问局部变量特性:局部变量必须被final讲)
写API的书写格式的例子:
package org.westos.版本2;
/**
*
* 该类是针对数组操作的一个工具类,里面有一些对数组操作的功能
* @author Apple
* @version V1.0
* */
public class ArrayTool {
//无参构造私有,目的为了不让外界其对象
private ArrayTool(){
}
/**
* 该方法是针对数组的遍历的方法,遍历的元素[元素1, 元素2, 元素, ....]
* @param arr :需要被遍历的数组
* */
public static void printArray(int[] arr){
System.out.print("[");
for(int x = 0 ; x < arr.length ; x ++){
if(x==arr.length-1){
System.out.println(arr[x]+"]");
}else{
System.out.print(arr[x]+", ");
}
}
}
/**
* 该方法是针对数组获取最大值的方法
* @param arr :需要被遍历的 数组,可以获取每一个元素
* @return 返回的就是数组中最大值
*
* */
public static int getMax(int[] arr){
//定义参照物
int max = arr[0] ;
//遍历其他索引
for(int x = 1 ; x < arr.length ;x ++){
//判断
if(arr[x]>max){
max = arr[x] ;
}
}
return max ;
}
/**
* 该方法是查询数组中的元素在数组中第一次出现的索引
* @param arr : 需要查询的数组
* @param value:需要被查找的远古时
* @return 如果查到了当前索引对应的元素,那么就直接返回当前索引,如果查不到,则返回-1
* */
public static int getIndex(int[] arr,int value){
//假设法
//定义一个索引:假设查不到
int index = -1 ;
//遍历数组
for(int x = 0 ; x < arr.length ; x ++){
//判断:如果刚好查到的x索引对应的元素和value相等,那么返回该索引
if(arr[x]==value){
//表查到了
//给索引遍历重新赋值
index = x ;
break ;
}
}
return index ;
}
}
作业:
1:博客自己总结这两天学的东西
2:形式参数和返回值问题
形式参数
基本类型:你要什么数据类型,在实际传参的时候就传什么数据类型。形式参数的改变对实际参数没有影响
引用类型:需要创建该类的对象
具体类:形参是具体类,需要创建该类对象
抽象类:形参是抽象类,需自定义一个子类,来进行实例化
接口:如果形参是接口,需自定义一个接口的子实现类,通过接口多态的形式给接口进行实例化
返回值类型
基本类型
引用类型:
具体类:直接返回该类对象
抽象类:需要返回该抽象类的子类对象
接口:返回该接口的子类实现对象
3:内部类的概述及访问特点
内部类的概述:在一个类中定义另一个类,那么把这种情况称为内部类
访问特点:内部类是可以直接访问外部类的成员,包括私有。
外部类想要访问内部类的成员,必须通过创建内部类的对象访问。
4:内部类的分类
成员内部类:在外部类的成员位置
局部内部类:在外部类的局部位置定义的这个类。
5:匿名内部类的格式和应用及面试题
匿名内部类的格式:
new 接口名或者类名(){
方法重写;
}
下去复习:常用类:
Object类,String类,StringBuffer类