继承
一,继承的概述:
●多个类中哦个存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为只要继承单独的那个类即可。
●多个类可以称为子类,单独这个类称为父类或者超类。
●子类可以直接访问父类中的非私有的属性和行为。
●通过extends关键字让类与类之间产生继承关系。
×class SubDemo extends Demo{}
●继承的出现提高了代码的复用性。
●继承的出现让类与类之间产生了关系,提供了多态的前提。
二,继承的特点:
●Java只支持单继承,不支持多继承。
×一个类之可以有一个父类,不可以有多个父类。
●Java支持多层继承(继承体系)
●定义继承需要注意:
×不要仅为了获取其他类中某个功能而去继承
×类与类之间要有所属("is a")关系,xx1是xx2的一种。
/*
子父类出现后,类成员的特点;
类中成员:
1,变量。
2,函数。
3,构造函数。
1,变量
如果子类中出现非私有的同名成员变量时,
子类要访问本类的变量,用this
子类要访问父类中的同名变量,用super。
super的使用和this的使用几乎一致。
this代表的是本类对象的引用。
super代表的是父类对象的引用。
*/
class Fu
{
int num = 4 ;
}
class Zi extends Fu
{
int num = 5 ;
void show ()
{
System.out.print(super.num);
}
}
class ExtendsDemo
{
public static void main(String [] args)
{
Zi z = new Zi ( ) ;
z.show( ) ;
System.out.print("~~~~");
System.out.println(z.num);
}
}
*
将学生和工人的共性描述提取出来,单独进行描述。
只要让学生和工人与单独描述的这个类有关系,就可以了。
继承:
1,提高了代码的复用性。
2,让类与类之间产生了关系。有了这个关系,才有了多态的特性。
注意:千万不要为了获取其他类的功能,简化代码而继承。
必须是类与类之间有所属关系才可以继承。所属关系 is a 。
*/
/*
java语言中:java只支持单继承,不支持多继承。
因为多继承容易带来安全隐患:当多个父类中定义了相同功能,当功能内容不同是,子类对象不确定要运行哪一个。
但是java保留这种机制,并用另一种体现形式来完成表示。叫多实现。
java支持多层继承。也就是一个继承体系,
如何使用一个继承体系中的功能呢?
想要使用体系,先查阅体系中父类的描述,因为父类中定义的是该类体系中的共性内容。
通过了解共性功能,就可以知道该体系的基本功能。
那么这个体系已经可以基本使用了。
那么具体调用时,要创建最子类的对象,为什么呢?
一是因为有可能父类不能创建对象。
二是创建子类对象可以使用更多的功能,包括基本的也包括特有的。
简单一句话:查阅父类功能,创建子类对象使用功能。
聚集:has a
聚合:
组合:
*/
class Person
{
String name;
int age;
}
class Student extends Person
{
void study( )
{
System.out.println("good study");
}
}
class Worker extends Person
{
void work( )
{
System.out.println("good work");
}
}
class JiCheng
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
三,super关键字
●super和this的用法相同
●this代表本类应用
●super代表父类应用
●当子类出现同名成员时,可以用super进行区分
●子类要调用父类构造函数时,可以使用super语句。
四,函数覆盖(override)
●子类中出现与父类一模一样的方法时,会出现覆盖操作,也称为重写或者复写。
●父类中的私有方法不可以被覆盖。
●在子类覆盖方法中,继续使用被覆盖的方法可以通过super.函数名获取。
●覆盖注意事项:
×覆盖时,子类方法权限一定要大于 等于父类方法权限
×静态只能覆盖静态
●覆盖的应用:
×当子类需要父类的功能,而功能主体子类有自己特有内容时,可以复写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
五,子类的实例化过程
●子类中所有的构造函数默认都会访问父类中空参数的构造函数
●因为每一个构造函数的第一行都有一条默认的语句super();
●子类会具备父类中的参数,所以要先明确父类是如何对这些数据初始化的。
●当父类中没有空参数的构造函数时,子类的构造函数必须通过this或者super语句指定要访问的构造函数。
六,final关键字
●final可以修饰类,方法,变量。
●final修饰的类不可以被继承。
●final修饰的方法不可以被覆盖。
●final修饰的变量是一个常量。只能被赋值一次。
●内部类只能访问被final修饰的局部变量。
七,抽象类
1,抽象类概述
●抽象类定义:
×抽象就是从多个事物中将共性的,本质的内容抽取出来。
×例如:狼和狗共性都是犬科,犬科就是抽象出来的概念。
●抽象类:
×Java中可以定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类
●抽象方法的由来:
×多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。
×例如:狼和狗都有吼叫的方法,可是吼叫内容是不一样的。所以抽象出来的犬科虽然有吼叫功能,但是并不明确吼叫细节。
2,抽象类的特点
●抽象类和抽象方法必须用abstract关键字来修饰。
●抽象方法只有方法声明,没有方法体,定义在抽象类中。
×格式:修饰符abstract 返回值类型 函数名(参数列表);
●抽象类不可以被实例化,也就是不可以用new创建对象。原因如下:
×抽象类是具体事物抽取出来的,本身是不具体的,没有对应的实例。例如:犬科是一个抽象的概念,真正存在 的是狼和狗。
×而且抽象类即使创建了对象,调用抽象方法也没有意义。
●抽象类通过其子类实例化,而子类需要覆盖掉抽象类中所有的抽象方法后才可以创建对象,否则该子类也是抽象类
3,抽象类举例代码
/*
当多个类中出现相同功能,但是功能主体不同,
这是可以进行向上抽取。这时,只抽取功能定义,而不抽取功能主体。
抽象:看不懂。
抽象类的特点:
1,抽象方法一定在抽象类中。
2,抽象方法和抽象类都必须被abstract关键字修饰。
3,抽象类不可以用new创建对象。因为调用抽象方法没意义。
4,抽象类中的抽象方法要被使用,必须由子类复写起所有的抽象方法后,建立子类对象调用。
如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。
抽象类和一般类没有太大的不同。
该如何描述事物,就如何描述事物,只不过,该事物出现了一些看不懂的东西。
这些不确定的部分,也是该事物的功能,需要明确出现。但是无法定义主体。
通过抽象方法来表示。
抽象类比一般类多个了抽象函数。就是在类中可以定义抽象方法。
抽象类不可以实例化。
特殊:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。
练习:
abstract 关键字,和哪些关键字不能共存。
final:被final修饰的类不能有子类。而被abstract修饰的类一定是一个父类。
private: 抽象类中的私有的抽象方法,不被子类所知,就无法被复写。
而抽象方法出现的就是需要被复写。
static:如果static可以修饰抽象方法,那么连对象都省了,直接类名调用就可以了。
可是抽象方法运行没意义。
抽象类中是否有构造函数?
有,抽象类是一个父类,要给子类提供实例的初始化。
*/
abstract class Student
{
abstract final void study();
//abstract void study1();
void sleep()
{
System.out.println("躺着");
}
}
/*
class ChongCiStudent extends Student
{
void study()
{
System.out.println("chongci study");
}
}
class BaseStudent extends Student
{
void study()
{
System.out.println("base study");
}
}
class AdvStudent extends Student
{
void study()
{
System.out.println("adv study");
}
}
*/
class AbstractDemo
{
public static void main(String[] args)
{
//new Student();
//new BaseStudent().study();
}
}
/*
假如我们在开发一个系统时需要对员工进行建模,员工包含 3 个属性:
姓名、工号以及工资。经理也是员工,除了含有员工的属性外,另为还有一个
奖金属性。请使用继承的思想设计出员工类和经理类。要求类中提供必要的方
法进行属性访问。
员工类:name id pay
经理类:继承了员工,并有自己特有的bonus。
*/
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 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("manager work");
}
}
class Pro extends Employee
{
Pro(String name,String id,double pay)
{
super(name,id,pay);
}
public void work()
{
System.out.println("pro work");
}
}
class
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
八,接口
●格式:
interface {}
●接口中的成员修饰符是固定的。
×成员常量:public static final
×成员函数:public abstract
●接口的出现将“多继承”通过另一种形式体现出来,即“多实现”。
1,接口的特点
●接口是对外暴露的规则。
●接口是程序的功能扩展。
●接口可以用来多实现。
●类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口。
●接口与接口之间可以有几次关系。
interface Inter
{
public static final double PI = 3.14 ;
public abstract void show ( ) ;
}
class Test implements Inter
{
public void show ( )
{
int x=0 ;
while ( x<10)
{
x++;
System.out.print(x+",");
}
}
}
class InterfaceDemo
{
public static void main(String[] args)
{
Test t = new Test ( ) ;
System.out.println( t.PI);
System.out.println( Test.PI);
System.out.println( Inter.PI);
t.show ( );
}
}
九,多态
定义:某一类事物的多种存在型态。
●体现:
父类或者接口的引用指向或者接收自己的子类对象。
●作用:
多态的存在提高了程序的扩展性和后期可维护性
●前提:
×需要存在继承或者实现关系
×要有覆盖操作
多态的特点:
●成员函数:
×编译时:要查看引用变量所属的类中是否有所调用的成员。
×在运行时:要查看对象所属的类中是否有所调用的成员。
●成员变量:
×只看引用变量所属的类。
/*
需求:数据库的操作。
数据是:用户信息。
1,连接数据库。JDBC Hibernate
2,操作数据库。
crud c create 创建 r read 读取 u update 修改 d delete删除
3,关闭数据库连接。
*/
interface UserInfoDao
{
public void add(User user);
public void delete(User user);
}
class UserInforByJDBC implements UserInfoDao
{
public void add (User user)
{
1, 连接数据库。;
2,使用sql添加语句添加数据。;
3,关闭连接。;
}
public void delete (User user)
{
1, 连接数据库。;
2,使用sql添加语句添加数据。;
3,关闭连接。;
}
}
class DBOperate
{
public static void main(String[] args)
{
UserInfoDao ui = new UserInforByJDBC();
ui.add(user);
ui.delete(user);
}
}
/*
需求:
电脑运行实例
电脑运行基于主板。
*/
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 DuoTaiDemo2
{
public static void main(String[] args)
{
MainBoard mb = new MainBoard ( ) ;
mb.run ( ) ;
mb.usePCI (new NetCard ( ) ) ;
}
}
内部类
●将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类,嵌套类)。
●访问特点:
×内部类可以直接访问外部类中的成员,包括私有成员。
×而外部类要访问内部类中的成员必须要建立内部类的对象。
内部类的位置
●内部类定义在成员位置上
×可以被private static成员修饰符修饰。
×被static修饰的内部类只能访问外部类中的静态成员。
●内部类定义在局部位置上
×也可以直接访问外部类中的成员。
×同时可以访问所在局部中的局部变量,但必须是被final修饰的。
/*
内部类的访问规则:
1,内部类可以直接访问外部类中的成员,包括私有。
之所以可以直接访问外部类中的成员,是因为内部类中持有一个外部类的引用,格式 外部类名.this
2,外部类要访问内部类,必须建立内部类对象。
访问格式:
1,当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中。
可以直接建立内部类对象。
格式:
外部类名.内部类名 变量名 = 外部类对象.内部类对象;
Outer.Inter in = new Outer().new Inter();
2,当内部类在成员位置上,就可以被成员修饰符所修饰。
比如,private:将内部类在外部类中进行封装。
static:内部类就具备static的特性。
当内部类被static修饰后,只能直接访问外部类中的static成员,出现了访问局限。
在外部其他类中,如何直接访问static内部类的非静态成员呢?
new Outer.Inter().function();
在外部其他类中,如何直接访问static内部类的静态成员呢?
Outer.Inter.function();
注意:当内部类中定义了静态成员,该内部类必须是static的。
当外部类中的静态方法访问内部类时,内部类也必须是static的。
当描述事物时,事物的内部还有事物,该事物用内部类来描述。
因为内部事物在使用外部事物的内容。
*/
class Outer
{
private int x = 3;
class Inter
{
int x = 5;
void function()
{
int x =8;
System.out.println("Inter="+Outer.this.x);
}
}
void method()
{
Inter in = new Inter();
in.function();
}
}
class InterClassDemo
{
public static void main(String[] args)
{
Outer out = new Outer();
out.method();
//直接访问内部类中的成员。
//Outer.Inter in = new Outer().new Inter();
//in.function();
}
}
匿名内部类
●就是内部类的简化写法。
●前提:
×内部类可以继承或实现一个外部类或者接口。
●格式为:
×new外部类名或者接口名(){覆盖类或者接口中的代码,(也可以自定义内容)}
●简单理解:
×就是建立一个带内容的外部类或者接口的子类匿名对象。
/*
匿名内部类:
1,匿名内部类其实就是内部类的简写格式。
2,定义匿名内部类的前提:
内部类必须是继承一个类或者实现接口.
3,匿名内部类的格式:new父类或者接口(){定义子类的内容}
4,其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖。
5,匿名内部类中定义的方法最好不要超过三个
*/
abstract class AbsDemo
{
abstract void show();
}
class Outer
{
int x = 3;
/*
class Inner extends AbsDemo
{
void show()
{
System.out.println("show:"+x);
}
}
*/
public void function()
{
//new Inner().show();
new AbsDemo()
{
void show()
{
System.out.println("x="+x);
}
}.show();
}
}
class InnerClassDemo2
{
public static void main(String[] args)
{
new Outer().function();
}
}
异常
●异常的体系
×Throwable
㈠Error
①通常出现重大问题如:运行的类不存在或者内存溢出等。
②不编写针对代码对其处理
㈡Excepyion
①在运行时运行出现的一些情况,可以通过try catch finally
●Exception和Error的子类名都是以父类名作为后缀。
Throwable中的方法
●getMessage()
×获取异常信息,返回字符串。
●toString()
×获取异常类名和异常信息,返回字符串。
●printStackTrace()
×获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
●printStackTrace(PrintStream s )
×通常用该方法将异常内容保存在日志文件中,以便查阅。
throws和throw
●/*
因为项目中会出现特有的问题。
而这些问题并未被java多描述并封装对象。
所以对于这些特有的问题可以被按照java对问题封装的思想。
将特有的问题,进行自定义的异常封装。
自定义异常。
需求:在本程序中,对于除数是负数,也视为是错误的是无法进行运算的。
那么就需要对这个问题进行自定义的描述。
当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作。
那么在内部try catch处理。
要么在函数上声明让调用者处理。
一般情况下,在函数内出现异常,函数上需要声明。
发现打印结果中只有异常的名称,却没有异常的信息。
因为自定义的异常并未定义信息。
如何定义异常信息呢?
因为父类中已经把异常信息的操作都完成了。
所以子类只要在构造时,将异常信息传递给父类通过super语句
那么就可以直接通过getMessage方法获取自定义的异常。
自定义异常:
必须是自定义类继承Exception。
继承Exception原因:
异常体系有一个特点:因为异常类和异常对象都被抛出。
他们都具有可抛性,这个可抛性是Throwable这个体系中独有特点。
只有这个体系中的类和对象才可以被throws和throw操作。
throws和throw的区别
throws使用在函数上。
throw使用在函数内。
throws后面跟的异常类。可以跟多个。用逗号隔开。
throw后跟的是异常对象。
*/
class FuShuException extends Exception//getMessage();
{
private int value;
FuShuException(String msg,int value)
{
super(msg);
this.value = value;
}
public int getvalue()
{
return value;
}
}
class Demo
{
int div(int a,int b)throws FuShuException
{
if(b<0)
throw new FuShuException("出现了除数是负数的情况/by fushu", b);//手动通过throw关键字抛出一个自定义异常对象。
return a/b;
}
}
class ExceptionDemo3
{
public static void main(String[] args)
{
Demo d = new Demo();
try
{
int x = d.div(4,-1);
System.out.println("x="+x);
}
catch (FuShuException e)
{
System.out.println(e.toString());
//System.out.println("除数出现负数啦!!");
System.out.println("错误的负数是:"+e.getvalue());
}
System.out.println("over");
}
}
异常处理
/*
异常的处理
java提供了特有的语句进行处理。
try
{
需要被检测的代码;
}
catch(异常类 变量)
{
处理异常的代码;(处理方式)
}
finally
{
一定会执行的语句;
}
3,对捕获到的异常对象进行常见方法操作。
String getMessage();获取异常信息。
在函数上声明异常。
便于提高安全性,让调用者进行处理。不处理编译失败。
对多异常的处理。
1,声明异常时,建议声明更为具体的异常。这样处理的可以更具体。
2,对方声明几个异常,就对应有几个catch块。不要定义多余的catch块。
如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。
建议在进行catch处理是,catch中一定要地定义具体处理方式。
不要简单定义一句e.printStackTrace(),
也不要简单的就书写一条输出语句。
*/
class Demo
{
int div(int a,int b)throws ArithmeticException,ArrayIndexOutOfBoundsException //在功能上通过throws的关键字声明了该功能有可能会出现问题。
{
int[] arr = new int[a];
System.out.println(arr[4]);
return a/b;
}
}
class ExceptionDemo
{
public static void main(String[] args)//throws Exception
{
Demo d= new Demo();
try
{
int x = d.div(4,0);
System.out.println("x="+x);
}
/*
catch (Exception e)
{
//System.out.println("除零啦!!");
//System.out.println(e.getMessage());// /by zero
System.out.println(e.toString());//异常名称:异常信息。
//e.printStackTrace();//异常名称,异常信息,异常出现的位置。
//其实jvm默认的异常处理机制,就是在调用printStackTrace方法。
//打印异常的堆栈的跟踪信息。
}
*/
catch(ArrayIndexOutOfBoundsException e)
{
System.out.println(e.toString());
System.out.println("角标越界啦!!");
}
System.out.println("over");
}
}
自定义异常
/*
Exception中有一个特殊的子类异常ArithmeticException运行时异常。
如果在函数内容抛出该异常,函数上可以不用声明,编译一样通过。
如果在函数上声明了该异常,调用者可以不用进行处理,编译一样通过。
之所以不愿在函数声明,是因为不需要让调用者处理。
当该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,希望停止程序后,
对代码进行修正。
自定义异常时:如果该异常的发生,无法在继续进行运算,
就让自定义异常继承RuntimeException。
对于异常分两种:
1,编译时被检测的异常。
2,被编译时不被检测的异常(运行时异常。RentimeException以及其子类)
*/
class Demo
{
int div(int a,int b)//throws ArithmeticException
{
if(b==0)
throw new ArithmeticException("被零除啦");
return a/b;
}
}
class ExceptionDemo4
{
public static void main(String[] args)
{
Demo d = new Demo();
int x = d.div(4,0);
System.out.println("x="+x);
System.out.println("over");
}
}
异常细节
●RuntimeException以及其子类如果在函数中被throw抛出,可以不用在函数上声明。
●一个方法被覆盖时,覆盖它的方法必须抛出相同的异常或异常的子类。
●如果父类抛出多个异常,那么重写(覆盖)方法必须抛出那些异常的一个子集,不能抛出新的异常。
●介绍异常在分层设计时的层内封装。
●例如:class LanPingException extends Exception
{
LanPingException(String message)
{
super(message);
}
}
class MaoYanException extends Exception
{
MaoYanException(String message)
{
super(message);
}
}
class NoPlanException extends Exception
{
NoPlanException(String msg)
{
super(msg);
}
}
class Computer
{
private int state = 3;
public void run()throws LanPingException,MaoYanException
{
if(state==2)
throw new LanPingException("蓝屏了");
if(state==3)
throw new MaoYanException("冒烟了");
System.out.println("电脑运行");
}
public void reset()
{
state = 1;
System.out.println("电脑重启");
}
}
class Teacher
{
private String name;
private Computer cmpt;
Teacher(String name)
{
this.name = name;
cmpt = new Computer();
}
public void prelect()throws NoPlanException
{
try
{
cmpt.run();
}
catch (LanPingException e)
{
cmpt.reset();
}
catch (MaoYanException e)
{
test();
throw new NoPlanException("课时无法继续"+e.getMessage());
}
System.out.println("讲课");
}
public void test()
{
System.out.println("练习");
}
}
class ExceptionTest
{
public static void main(String[] args)
{
Teacher t = new Teacher("毕老师");
try
{
t.prelect();
}
catch (NoPlanException e)
{
System.out.println(e.toString());
System.out.println("换老师或者放假");
}
}
}
包(package)
●对类文件进行分类管理。
●给类提供多层命名空间。
●写在程序文件的第一行。
●类名的全称是 包名.类名。
●包也是一种封装形式。
包之间的访问
●被访问的包中的类权限必须是public的。
●类中的成员权限:public或者protected
●protected是为其他包中的子类提供的一种权限
import
●简化类名。
●一个程序文件中只有一个package,可以有多个import。
●用来导包中的类,不导入包中的包。
●通常写import mypack.Demo;
而不写import mypack.*;
jar包
●Java的压缩包
×方便项目的携带。
×方便于使用,只要在classpath设置jar路径即可。
●数据库驱动,SSH框架等都是以jar包体现的。
jar包的操作
通过jar.exe工具对jar的操作。
×创建jar包
jar -tvf mypack.jar packa packb
×查看jar包
jar -tvf mypack.jar [>定向文件]
×解压缩
jar -xvf mypack.jar
×自定义jar包的清单文件
jar -cvfm mypack.jar mf.txt packa packb