------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
二、面向对象基础
1. 概念
现实世界中,随处可见的一种事物就是对象,对象是事物存在的实体,如人类、书桌、计算机、高楼大厦等。人类解决问题的方式总是将复杂的事物简单化,于是就会思考这些对象都是由哪些部分组成的。通常都会将对象划分为两个部分,即动态部分与静态部分。静态部分,顾名思义就是不能动的部分,这个部分被称为“属性”,任何对象都会具备其自身属性,如一个人,它包括高矮、胖瘦、性别、年龄等属性。然而具有这些属性的人会执行哪些动作也是一个值得探讨的部分,这个人可以哭泣、微笑、说话、行走,这些是这个人具备的行为(动态部分),人类通过探讨对象的属性和观察对象的行为了解对象。
类是封装对象的属性和行为的载体,反过来说具有相同属性和行为的一类实体被称为类。例如一个鸟类,鸟类封装了所有鸟的共同属性和应具有的行为用java语言对现实生活中的事物进行描述是通过类的形式来体现的。怎么描述呢?对于事物描述通常只关注两方面:一个是属性,一个是行为。只要明确该事物的属性和行为并定义在类中即可。那么类与对象之间是什么关系呢?类:事物的描述,对象:该类事物的实例,在java中通过new来创建的。
类与对象的概念:
对象在内存中的存在:
成员变量和局部变量的区别:
1,
成员变量定义在类中,整个类中都可以访问。
局部变量定义在函数,语句,局部代码块中,只在所属的区域有效。
2,
成员变量存在于堆内存的对象中。
局部变量存在于栈内存的方法中。
3,
成员变量随着对象的创建而存在,随着对象的消失而消失。
局部变量随着所属区域的执行而存在,随着所属区域的结束而释放。
4,
成员变量都有默认初始化值。
局部变量没有默认初始化值。
2. 封装(Encapsulation)
class Person
{
private int age;
public void setAge(int a)
{
age = a;
}
void speak()
{
System.out.println("age="+age);
}
}
class PersonDemo
{
public static void main(String[] args)
{
Person p = new Person();
p.setAge(20);
p.speak();
}
}
3. 构造函数与构造代码块
<span style="font-family:Microsoft YaHei;font-size:14px;">/*
对象一建立就会调用与之对应的构造函数。
构造函数的作用:可以用于给对象进行初始化。
构造函数的小细节:
当一个类中没有定义的函数时,那么系统就会默认给该类加入一个空参数的构造函数。
当在类中自定义了构造函数后
*/
</span>
一个对象的建立,构造方法只运行一次,而普通方法可以多次运行。
class
{
public static void main(String[] args)
{
new Person();
Person p = new Person();
Person p1 = new Person("zhangsan");
}
}
class Person
{
private String name;
/*构造代码块
对象一初始化就运行,而且优先于构造函数执行。
和构造函数的区别:
构造代码块是给所有对象统一初始化,
而构造函数是给对应的对象初始化。
*/
{
System.out.println("person code run");
}
Person()
{
System.out.println("A:name="+name+",,age="+age);
}
Person(String n)
{
name = n;
System.out.println("B:name="+name+",,age="+age);
}
}
4. this关键字
看上去是用于区分成员变量和局部变量的
this为什么可以解决这个问题?this到底代表的是什么?
根据我所理解,this指代的是当前所指示的这个对象,我们把name传进去其实是把name赋值给我们所建立的这个对象,所以用this关键字标示一下指代当前对象的成员变量
this:代表本类对象,代表他所在函数所属对象的引用,简单说,哪个对象在调用this所在的函数,this就指代哪个对象
this应用:当定义类中功能时,该函数内部要用到调用该函数的对象时,这时用this来表示这个对象。
但凡本类功能内部使用了本类对象,就要用到this。
class Demo
{
public static void main(String[] args)
{
new Person();
Person p = new Person();
Person p1 = new Person("zhangsan");
}
}
class Person
{
private String name;
private int age;
/*构造代码块
对象一初始化就运行,而且优先于构造函数执行。
和构造函数的区别:
构造代码块是给所有对象统一初始化,
而构造函数是给对应的对象初始化。
*/
{
System.out.println("person code run");
}
Person()
{
System.out.println("A:name="+name+",,age="+age);
}
Person(String name)
{
this.name = name;
System.out.println("B:name="+name+",,age="+age);
}
Person(String name,int age)
{
this.name = name; //用this关键字用来指示成员变量
//如果局部有,就在局部找,如果没有就到局部变量里找
this.age = age;
}
public void speak()
{
System.out.println("name="+name+"...age="+age);
}
}
class Person
{
private int age;
Person(int age)
{
this.age = age;
}
/*
需求:给人定义一个用于比较年龄是否相同的功能,也就是否是同龄人
*/
public boolean compare(Person p)
{
return this.age==age;
}
}
class Demo
{
public static void main(String[] args)
{
Person p1 = new Person(20);
Person p2 = new Person(25);
boolean b = p1.compare(p2);
System.out.println(b);
}
}
this语句:用于构造函数之间互相调用
class Person
{
private String name;
private int age;
Person(String name)
{
this.name = name;
}
Person(String name,int age)
{
this(name); //调用Person(String name)构造方法
this.age = age;
}
}
class Demo
{
public static void main(String[] args)
{
Person p= new Person("lisi",30);
}
}
5. static关键字和main函数
静态:static
用法:是一个修饰符,用于修饰成员(成员变量,成员函数)
当成员被静态修饰后,就多了一个调用方式,除了可以被对象调用外,还可以直接被类名调用
static的特点:
1,static是一个修饰符,用于修饰成员。
2,static修饰的成员被所有的对象所共享。
3,static优先于对象存在,因为static的成员随着类的加载就已经存在了。
4,static修饰的成员多了一种调用方式,就可以直接被类名所调用 。 类名.静态成员 。
5,static修饰的数据是共享数据,对象中的存储的是特有数据。
成员变量和静态变量的区别?
1,两个变量的生命周期不同。
成员变量随着对象的创建而存在,随着对象的被回收而释放。
静态变量随着类的加载而存在,随着类的消失而消失。
2,调用方式不同。
成员变量只能被对象调用。
静态变量可以被对象调用,还可以被类名调用。
3,别名不同。
成员变量也称为实例变量。
静态变量称为类变量。
4,数据存储位置不同。
成员变量数据存储在堆内存的对象中,所以也叫对象的特有数据.
静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据.
静态使用的注意事项:
1,静态方法只能访问静态成员。(非静态既可以访问静态,又可以访问非静态)
2,静态方法中不可以使用this或者super关键字。
3,主函数是静态的。
<span style="font-family:Arial;font-size:12px;">class Person
{
private String name;
private int age;
static String country = "CN";
public Person(String name,int age)
{
this.name = name;
this.age = age;
}
public void show()
{
System.out.println(Person.country+":"+this.name+":"+this.age);
}
//静态方法中存在调用静态变量的行为,可以直接类名调用
public static void method()
{
System.out.println(Person.country);
}
}
class StaticDemo2
{
public static void main(String[] args) throws Exception
{
//线程暂停5秒
Thread.sleep(5000);
//类名调用静态方法无需对象
Person.method();
//创建对象后可以调用非静态方法
Person p = new Person("java",20);
p.show();
}
}</span>
main函数
public static void main(String[] args)
主函数是一个特殊函数,作为程序的入口,可以被jvm调用
主函数特殊之处:
1,格式是固定的。
2,被jvm所识别和调用。
public:代表该函数的访问权限必须是最大的。
static:代表主函数随着类的加载就已经存在了,不需要对象的,直接用主函数所属类名调用即可。
void:主函数没有具体的返回值。
main:函数名,不是关键字,只是一个jvm识别的固定的名字。
String[] args:这是主函数的参数列表,是一个数组类型的参数,而且元素都是字符串类型。
class MainDemo
{
public static void main(String[] args) //new String[0]
{
/**/
// System.out.println(args);//[Ljava.lang.String;@c17164
System.out.println(args.length);
for(int x=0; x<args.length; x++)
System.out.println(args[x]);
}
}
6. 静态应用
什么时候使用静态:
class Demo
{
int age ;
static int num = 9;
Demo(int age)
{
this.age = age;
}
public static void speak()
{
System.out.println(num);
}
public void show()
{
System.out.println(age);
}
}
class StaticDemo3
{
public static void main(String[] args)
{
// Demo d = new Demo(30);
// d.speak();
Demo.speak();
// System.out.println("Hello World!");
}
}
静态的应用-->创建静态工具类:
/*
每个用用程序中都有共性的功能,可以将这些功能进行抽取,独立封装,以便复用
*/
class ArrayTool
{private ArrayTool(){} //构造函数私有化防止建立对象
//获取最大值功能
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;
}
//获取最小值功能
public static int getMin(int[] arr)
{
int min = arr[0];
for(int x=1;x<arr.length;x++)
{
if(arr[x]<min)
min = arr[x];
}
return min;
}
//选择排序
public static void selectSort(int[] arr)
{
for(int x=0;x<arr.length-1;x++)
{
for(int y=x+1;y<arr.length;y++)
{
if(arr[y]<arr[x])
{
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
}
}
}
//冒泡排序
public static void bubbleSort(int[] arr)
{
for (int x=0;x<arr.length ;x++ )
{
for (int y=0;y<arr.length-x-1 ;y++ )
{
if (arr[y]>arr[y+1])
{
int temp = arr[y];
arr[y] = arr[y+1];
arr[y+1] = temp;
}
}
}
}
//位置置换
public static void swap(int[] arr,int a,int b)
{
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
//打印数组
public static void printArr(int[] arr)
{
System.out.print("[");
for (int x=0;x<arr.length ;x++ )
{
if (x!=arr.length)
{
System.out.print(arr[x]+",");
}
else
System.out.print(arr[x]);
}
System.out.print("]");
}
}
使用静态工具类:
class TestTool
{
public static void main(String[] args)
{
int[] arr = {1,5,7,8,6,2,3};
ArrayTool.printArr(arr); //直接类名调用
}
}
7. 帮助文档的制作
在工具类中用/***/来标示帮助内容,@param 接收参数 @return 返回参数 等等
生成帮助文档时在命令行输入:javadoc -d myhelp -author -version ArrayTool.java 其中-d标示出帮助文档所存目录,-author列出作者,-version列出版本号
/*
每个用用程序中都有共性的功能,可以将这些功能进行抽取,独立封装,以便复用
*/
public class ArrayTool
{
/**
构造函数私有化
*/
private ArrayTool(){}
//获取最大值功能
/**
获取一个整形数组中的最大值
@param arr 接受一个int型的数组
@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 接受一个int型的数组
@return 会返回该数组中的最小值
*/
//获取最小值功能
public static int getMin(int[] arr)
{
int min = arr[0];
for(int x=1;x<arr.length;x++)
{
if(arr[x]<min)
min = arr[x];
}
return min;
}
/**
对int数组进行选择排序
@param arr 接受一个int型的数组
*/
//选择排序
public static void selectSort(int[] arr)
{
for(int x=0;x<arr.length-1;x++)
{
for(int y=x+1;y<arr.length;y++)
{
if(arr[y]<arr[x])
{
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
}
}
}
/**
对int数组进行冒泡排序
@param arr 接受一个int型的数组
*/
//冒泡排序
public static void bubbleSort(int[] arr)
{
for (int x=0;x<arr.length ;x++ )
{
for (int y=0;y<arr.length-x-1 ;y++ )
{
if (arr[y]>arr[y+1])
{
int temp = arr[y];
arr[y] = arr[y+1];
arr[y+1] = temp;
}
}
}
}
/**
对int数组的元素进行位置置换
@param arr 接受一个int型的数组
@param a 要置换的位置
@param b 要置换的位置
*/
//位置置换
public static void swap(int[] arr,int a,int b)
{
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
/**
对int数组进行打印
@param arr 接受一个int型的数组
*/
//打印数组
public static void printArr(int[] arr)
{
System.out.print("[");
for (int x=0;x<arr.length ;x++ )
{
if (x!=arr.length)
{
System.out.print(arr[x]+",");
}
else
System.out.print(arr[x]);
}
System.out.print("]");
}
}
8. 对象初始化与调用成员的过程
Person p = new Person("zhangsan",20);
这句话都做了那些事?
1,因为new用到了Person.class文件,所以先找到Person.class文件加载进内存
2,执行该类中的static代码块,如果有的话,给Person类进行初始化,
3,在堆内存中开辟空间,分配内存地址。
4,在堆内存中建立对象的特有属性并进行默认初始化,
5,对属性进行显示初始化
6,对对象进行构造代码块初始化,
7,对对象进行对应的构造函数初始化
8,将内存地址赋值给内存中的p变量
9. 单例设计模式
我们需要一个类只能创建一个对象,也就是同一时刻在内存中只存在一个对象
/*
设计模式:对问题行之有效的解决方式。其实它是一种思想。
1,单例设计模式。
解决的问题:可以保证一个类在内存中的对象唯一性。
必须对于多个程序使用同一个配置信息对象时,就需要保证该对象的唯一性。
如何保证对象唯一性呢?
1,不允许其他程序用new创建该类对象。
2,在该类创建一个本类实例。
3,对外提供一个方法让其他程序可以获取该对象。
步骤:
1,私有化该类构造函数。
2,通过new在本类中创建一个本类对象。
3,定义一个公有的方法,将创建的对象返回。
*/
//饿汉式,类一加载,对象就已经存在了。
class Single
{
private static Single s = new Single();
private Single(){}
public static Single getInstance()
{
return s;
}
}
//懒汉式,类加载进来,没有对象,只有调用了getInstance方法时,才会创建对象
//也称为延迟加载形式。
class Single2
{
private static Single2 s = null;
private Single2(){}
public static Single2 getInstance()
{
if(s==null)
s = new Single2();
return s;
}
}
class Test
{
private int num;
private static Test t = new Test();
private Test(){}
public static Test getInstance()
{
return t;
}
public void setNum(int num)
{
this.num = num;
}
public int getNum()
{
return num;
}
}
class SingleDemo
{
public static void main(String[] args)
{
Single s1 = Single.getInstance();
Single s2 = Single.getInstance();
System.out.println(s1==s2);
Test t1 = Test.getInstance();
Test t2 = Test.getInstance();
t1.setNum(10);
t2.setNum(20);
System.out.println(t1.getNum());
System.out.println(t2.getNum());
}
}
10. 继承
1.继承
继承就是一个类具有另一个类的所有特征并且会有自己的特有特征
继承的好处:
1,提高了代码的复用性。
2,让类与类之间产生了关系,给第三个特征多态提供了前提.
java中支持单继承。不直接支持多继承,但对C++中的多继承机制进行改良。
单继承:一个子类只能有一个直接父类。
多继承:一个子类可以有多个直接父类(java中不允许,进行改良)
不直接支持,因为多个父类中有相同成员,会产生调用不确定性。
在java中是通过"多实现"的方式来体现。
java支持多层(多重)继承。
C继承B,B继承A。
就会出现继承体系。
当要使用一个继承体系时,
1,查看该体系中的顶层类,了解该体系的基本功能。
2,创建体系中的最子类对象,完成功能的使用。
什么时候定义继承呢?
当类与类之间存在着所属关系的时候,就定义继承。xxx是yyy中的一种。 xxx extends yyy
所属关系: is a 关系。
继承中的成员变量:
基本格式:
class Demo
{
void show1(){}
}
class DemoA extends Demo
{
void show1(){}
void show2(){}
}
class DemoB extends Demo
{
void show1(){}
void show3(){}
}
例子:
class Person
{
String name;
int age;
}
class Student extends Person//Student继承Person
{
String name;
int age;
void study()
{
System.out.println(name+"..student study.."+age);
}
}
class Worker extends Person
{
// String name;
// int age;
void work()
{
System.out.println("worker work");
}
}
class ExtendsDemo
{
public static void main(String[] args)
{
Student s = new Student();
s.name= "zhangsan";
s.age = 22;
s.study();
Worker w = new Worker();
w.work();
}
}
变量:
如果子类中出现非私有的同名成员变量时,子类要访问本类中的变量,用this,子类要访问父类的同名变量,用super
super的使用和this几乎一致
this代表的是本类对象的引用,super代表的是父类对象的引用
函数:
当子父类中出现成员函数一模一样的情况,会运行子类的函数。
这种现象,称为覆盖操作。这时函数在子父类中的特性。
函数两个特性:
1,重载。同一个类中。overload
2,覆盖。子类中。覆盖也称为重写,覆写。override
覆盖注意事项:
1,子类方法覆盖父类方法时,子类权限必须要大于等于父类的权限。
2,静态只能覆盖静态,或被静态覆盖。
构造函数:
/*
子父类中的构造函数的特点。
在子类构造对象时,发现,访问子类构造函数时,父类也运行了。
为什么呢?
原因是:在子类的构造函数中第一行有一个默认的隐式语句。 super();
子类的实例化过程:子类中所有的构造函数默认都会访问父类中的空参数的构造函数。
为什么子类实例化的时候要访问父类中的构造函数呢?
那是因为子类继承了父类,获取到了父类中内容(属性),所以在使用父类内容之前,
要先看父类是如何对自己的内容进行初始化的。
所以子类在构造对象时,必须访问父类中的构造函数。
为什么完成这个必须的动作,就在子类的构造函数中加入了super()语句。
如果父类中没有定义空参数构造函数,那么子类的构造函数必须用super明确要调用
父类中哪个构造函数。同时子类构造函数中如果使用this调用了本类构造函数时,
那么super就没有了,因为super和this都只能定义第一行。所以只能有一个。
但是可以保证的是,子类中肯定会有其他的构造函数访问父类的构造函数。
注意:supre语句必须要定义在子类构造函数的第一行。因为父类的初始化动作要先完成。
*/
class Fu
{
int num ;
Fu()
{
num =10;
System.out.println("A fu run");
}
Fu(int x)
{
System.out.println("B fu run..."+x);
}
}
class Zi extends Fu
{
int num;
Zi()
{
//super();//调用的就是父类中的空参数的构造函数。
System.out.println("C zi run"+num);
}
Zi(int x)
{
this();
//super();
// super(x);
System.out.println("D zi run "+x);
}
}
class ExtendsDemo4
{
public static void main(String[] args)
{
new Zi(6);
}
}
class Demo//extends Object
{
/*
Demo()
{
super();
return;
}
*/
}
11. 抽象类
抽象类:
抽象:笼统,模糊,不具体。
特点:
1,方法只有声明没有实现时,该方法就是抽象方法,需要被abstract修饰。
抽象方法必须定义在抽象类中。该类必须也被abstract修饰。
2,抽象类不可以被实例化。为什么?因为调用抽象方法没意义。
3,抽象类必须有其子类覆盖了所有的抽象方法后,该子类才可以实例化。
否则,这个子类还是抽象类。
1,抽象类中有构造函数吗?
有,用于给子类对象进行初始化。
2,抽象类可以不定义抽象方法吗?
可以的。 但是很少见,目的就是不让该类创建对象。AWT的适配器对象就是这种类。
通常这个类中的方法有方法体,但是却没有内容。
3,抽象关键字不可以和那些关键字共存?
private 不行
static 不行
final 不行
4,抽象类和一般类的异同点。
相同点:
抽象类和一般类都是用来描述事物的,都在内部定了成员。
不同:
1,一般类有足够的信息描述事物。
抽象类描述事物的信息有可能不足。
2,一般类中不能定义抽象方法,只能定非抽象方法。
抽象类中可定义抽象方法,同时也可以定义非抽象方法。
3,一般类可以被实例化。
抽象类不可以被实例化。
5,抽象类一定是个父类吗?
是的。因为需要子类覆盖其方法后才可以对子类实例化。
abstract class Demo
{
void show1()
{}
void show2()
{}
}
/*
雇员示例:
需求:公司中程序员有姓名,工号,薪水,工作内容。
项目经理除了有姓名,工号,薪水,还有奖金,工作内容。
对给出需求进行数据建模。
分析:
在这个问题领域中,先找出涉及的对象。
通过名词提炼法。
程序员:
属性:姓名,工号,薪水、
行为:工作。
经理:
属性:姓名,工号,薪水,奖金。
行为:工作。
程序员和经理不存在着直接继承关系,
但是程序员和经理却具有共性内容。
可以进行抽取。因为他们都是公司的雇员
可以将程序员和经理进行抽取.建立体系.
*/
//描述雇员。
abstract class Employee
{
private String name;
private String id;
private double pay;
Employee(String name,String id,double pay)
{
this.name = name;
this.id = id;
this.pay = pay;
}
public abstract void work();
}
//描述程序员。
class Programmer extends Employee
{
Programmer(String name,String id,double pay)
{
super(name,id,pay);
}
public void work()
{
System.out.println("code...");
}
}
//描述经理。
class Manager extends Employee
{
private int bonus;
Manager(String name,String id,double pay,int bonus)
{
super(name,id,pay);
this.bonus = bonus;
}
public void work()
{
System.out.println("manage");
}
}
class AbstractTest
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
class Student extends Person
{
Student(String name,int age)
{
super(name,age);
}
}
class Worker extends Person
{
Worker(String name,int age)
{
super(name,age);
}
}
12. 接口
/*
abstract class AbsDemo
{
abstract void show1();
abstract void show2();
}
当一个抽象类中的方法都是抽象的时候,这时可以将该抽象类用
另一种形式定义和表示,就是 接口 interface。
*/
//定义接口使用的关键字不是class,是interface.
/*
对于接口当中常见的成员:而且这些成员都有固定的修饰符。
1,全局常量: public static final
2,抽象方法。public abstract
由此得出结论,接口中的成员都是公共的权限.
*/
interface Demo
{
public static final int NUM = 4;
public abstract void show1();
public abstract void show2();
}
//类与类之间是继承关系,类与接口直接是实现关系。
/*
接口不可以实例化。
只能由实现了接口的子类并覆盖了接口中所有的抽象方法后,该子类才可以实例化。
否则,这个子类就是一个抽象类。
*/
class DemoImpl implements /*实现*/Demo
{
public void show1()
{}
public void show2()
{
}
}
/*
在java中不直接支持多继承,因为会出现调用的不确定性。
所以java将多继承机制进行改良,在java中变成了多实现。
一个类可以实现多个接口。
*/
interface A
{
public void show();
}
interface Z
{
public int add(int a,int b);
}
class Test implements A,Z//多实现
{
public int add(int a,int b)
{
return a+b+3;
}
/**/
public void show(){}
}
/*
一个类在继承另一个类的同时,还可以实现多个接口。
*/
class Q
{
public void method()
{}
}
abstract class Test2 extends Q implements A,Z
{
}
/*
接口的出现避免了单继承的局限性。
*/
interface CC
{
void show();
}
interface MM
{
void method();
}
interface QQ extends CC,MM//接口与接口之间是继承关系,而且接口可以多继承。
{
void function();
}
class WW implements QQ
{
//覆盖3个方法。
public void show(){}
public void method(){}
public void function(){}
}
class InterfaceDemo
{
public static void main(String[] args)
{
Test t = new Test();
t.show();
DemoImpl d = new DemoImpl();
System.out.println(d.NUM);
System.out.println(DemoImpl.NUM);
System.out.println(Demo.NUM);
}
}
13. 多态
1,多态的体现
父类对象的引用指向了自己的子类对象。
父类的引用也可以接收自己的子类对象
2,多态的前提
必须是类与类之间有关系,要么继承,要么实现
通常还有一个前提:存在覆盖
3,多态的好处
多态的出现大大提高程序的扩展性
4,多态的弊端
虽然提高了扩展性,但是只能使用父类的引用访问父类中的成员
5,多态的应用
6,多态的出现代码中的特点(多态使用注意事项)
在多态中成员函数的特点:(动态绑定和静态绑定)
在编译时期:参阅引用型变量所属的类中是否有调用的方法,如果有,编译通过,如果没有编译失败
在运行时期:参阅对象所述的类中是否有调用的方法
简单总结就是,成员函数在多态中,编译看左边,运行看右边
/*
基础班学生
学习,睡觉
高级班学生
学习,睡觉
可以将这两类事物进行抽取
*/
abstract class Student
{
public abstract void study();
public viud sleep()
{
System.out.println("躺着睡");
}
}
class BaseStudent extends Student
{
public void study()
{
System.out.println("base study");
}
public void sleep()
{
System.out.println("坐着睡");
}
}
class AdvStudent extends Student
{
public void study()
{
System.out.println("adv study");
}
}
class DoStudent
{
public void doSome(Student s)
{
s.study();
s.sleep();
}
}
class Demo
{
public static void main(String[] args)
{
DoStudent ds = new DoStudent();
ds.doSome(new BaseStudent());
ds.doSome(new AdvStudent());
/*
BaseStudent bs = new BaseStudent();
bs.study();
bs.sleep();
AdvStudent as = new AdvStudent();
as.study();
as.sleep();
*/
}
}
模板方法设计模式
/*
需求:获取一段程序运行的时间
原理:获取程序开始和结束的时间并相减就可以
*/
abstract class GetTime
{
public final void getTime()//用final修饰防止被复写
{
long start = System.currentTimeMillis();
runcode();
long end = System.currentTimeMillis();
System.out.println("毫秒:"+(end-start));
}
public abstract void runcode();//因为不明确方法主体所以使用抽象方法
}
class Test extends GetTime
{
public void runcode()
{
for(int x=0;x<1000;x++)
{
System.out.println(x);
}
}
}
多态降低耦合性示例:
1,未利用多态的程序
/*
需求:
电脑运行实例,
电脑运行基于主板
*/
class MainBoard
{
public void run()
{
System.out.println("mainboard run");
}
public void useNetCard(NetCard c)
{
c.open();
c.close();
}
}
class NetCard
{
public void open()
{
System.out.println("netcard open");
}
public void close()
{
System.out.println("netcard close");
}
}
class Computer
{
public static void main(String[] args)
{
MainBoard mb = new MainBoard();
mb.run();
mb.useNetCard();
}
}
使用多态:(接口)
interface PCI
{
public void open();
public void close();
}
class MainBoard
{
public void run()
{
System.out.println("mainboard run");
}
public void usePCI(PCI p)
{
if(p!=null)
{
p.open();
p.close();
}
}
}
class NetCard implements PCI
{
public void open()
{
System.out.println("netcard open");
}
public void close()
{
System.out.println("netcard close");
}
}
class Demo2
{
public static void main(String[] args)
{
MainBoard mb = new MainBoard();
mb.run();
}
}
14. 内部类
内部类的访问规则:
1,内部类可以直接访问外部类的成员,包括私有。
之所以可以直接访问外部类的成员,是因为内部类中持有了一个外部类的引用,格式 外部类名.this
2,外部类要访问内部类,必须建立内部类对象。
访问格式:
1,当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中,可以直接建立内部类对象
格式:
外部类名.内部类名 变量名 = 外部类对象.内部类对象;,2,当内部类在成员位置上,就可以被成员修饰符所修饰。
比如,private:将内部类在外部类中进行封装,static:内部类就具备static特性,当内部类被静态修饰后,只能直接访问外部类静态成员
/*
内部类
*/
class Outer
{
int x=3;
class Inner
{
void function()
{
System.out.println("Inner:"+x);
}
}
void method()
{
Inner in = new Inner();
in.function();
}
}
class Main
{
public static void main(String[] args)
{
Outer out = new Outer();
//内部类访问
Outer.Inner in = new Outer().new Inner();
out.method();
}
}
15. 异常
异常:就是程序在运行时出现的不正常情况。
异常由来:问题也是现实生活中的一个具体事物,也可以通过java的类的形式进行描述,并封装成对象。
其实就是java对不正常的情况进行描述后的对象体现。
对于问题的划分:两种:一种是严重的问题,一种是非严重的问题
对于严重的,java通过Error类进行描述。
对于不严重的,java通过Exception类进行描述。
异常的体系:
Throwanle
Error:通常出现大量问题如,运行的类不存在或者内存溢出等,不编写针对代码对其处理
Exception:在运行时运行出现的一些情况,可以通过try catch finally来处理
处理方法:
1,
try{
//此处放异常的代码
}
catch(Exception e){
//此处是如果try里面的语句发生异常不能执行,就执行catch里的语句
}
finally{
//此处放必须会执行的代码
}
2,
在功能上通过throws关键字声明了该功能可能出现问题。
throws Exception
多异常处理 :
1,声明宜昌市,建议声明更为具体的异常,这样处理的可以更具体。
2,对方声明几个异常,就对应有几个catch块,不要定义多余的
如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面
建议在进行catch处理时,catch中一定要定义具体的处理方式。
不要简单定义一句e.printStackTrace(),也不要简单的就书写一条输出语句
throws和throw区别
throws:使用在函数上
throw使用在函数内
throws后面跟的是异常类,可以跟多个,用逗号隔开。
throw后跟的是异常对象。