您的位置:首页 > 职场人生

黑马程序员——java基础--面向对象基础

2015-05-17 08:07 513 查看
------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

二、面向对象基础

1. 概念

   现实世界中,随处可见的一种事物就是对象,对象是事物存在的实体,如人类、书桌、计算机、高楼大厦等。人类解决问题的方式总是将复杂的事物简单化,于是就会思考这些对象都是由哪些部分组成的。通常都会将对象划分为两个部分,即动态部分与静态部分。静态部分,顾名思义就是不能动的部分,这个部分被称为“属性”,任何对象都会具备其自身属性,如一个人,它包括高矮、胖瘦、性别、年龄等属性。然而具有这些属性的人会执行哪些动作也是一个值得探讨的部分,这个人可以哭泣、微笑、说话、行走,这些是这个人具备的行为(动态部分),人类通过探讨对象的属性和观察对象的行为了解对象。
    类是封装对象的属性和行为的载体,反过来说具有相同属性和行为的一类实体被称为类。例如一个鸟类,鸟类封装了所有鸟的共同属性和应具有的行为用java语言对现实生活中的事物进行描述是通过类的形式来体现的。怎么描述呢?对于事物描述通常只关注两方面:一个是属性,一个是行为。只要明确该事物的属性和行为并定义在类中即可。那么类与对象之间是什么关系呢?类:事物的描述,对象:该类事物的实例,在java中通过new来创建的。

类与对象的概念:



对象在内存中的存在:



成员变量和局部变量的区别:

1,

成员变量定义在类中,整个类中都可以访问。

局部变量定义在函数,语句,局部代码块中,只在所属的区域有效。

2,

成员变量存在于堆内存的对象中。

局部变量存在于栈内存的方法中。

3,

成员变量随着对象的创建而存在,随着对象的消失而消失。

局部变量随着所属区域的执行而存在,随着所属区域的结束而释放。

4,

成员变量都有默认初始化值。

局部变量没有默认初始化值。

2. 封装(Encapsulation)

封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式
好处:1,将变化隔离;2,便于使用;3,提高重用性;4,提高安全性。
封装原则:
1,将不需要对外提供的内容都隐藏起来。
2,把属性都隐藏,提供公共方法对其访问。
将age私有化以后,类以外即使建立了对象也不能直接访问,但是人应该有年龄,就需要在Person类中提供对应访问age的方式
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. 构造函数与构造代码块

特点:
1,函数名与类名相同
2,不用定义返回值类型
3,不可以写return语句
作用:
给对象进行初始化。
注意:
1,默认构造函数的特点。
2,多个构造函数是以重载的形式存在的。
<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语句:用于构造函数之间互相调用

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;
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(),也不要简单的就书写一条输出语句

[b]throws和throw区别


throws:使用在函数上

throw使用在函数内

throws后面跟的是异常类,可以跟多个,用逗号隔开。

throw后跟的是异常对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java