链接到上一篇:http://t.csdnimg.cn/V7rvT
一、类的继承
1.1概述
继承是面向对象的三大特征之一,可以使子类具有父类的属性和方法,还可以在子类中重新定义添加属性和方法。
- 关键字:extends
- 格式:
public class 子类名 extends 父类名{ }
父类:也称为基类、超类
子类:也称为派生类
- 继承的好处:
- 可以把多个子类中重复的代码抽取到父类中,提高代码的复用性。
- 子类可以在父类的基础上增加其他功能,使子类更强大。
- 什么时候使用继承:
- 当类与类之间存在相同(共性)的内容,并满足子类是父类中的一种,就可以考虑使用继承优化代码。
- 特点
- 子类能继承父类非私有成员,私有的不能被继承。
- 子类的对象是由子类父类共同完成的。
例:
//父类
public class A{
public int i;
public void print1(){
System.out.println("print1");
}
private int j;
private void print2(){
System.out.println("print2");
}
//子类
public class B extends A{ //子类是可以继承父类的非私有成员的。
public void print3(){
System.out.println(i);
print 1();
System.out.println(j);
print 2(); //会报错,在父类中j已被私有,不能继承。
//Test类
B b = new B();
System.out.println(b,i);
b.print1();
b.print3();
注意:
JAVA中只支持单继承,不支持多继承,但支持多层继承。
class C extends A,B{ } //错 class B extends A { }; class C extends B { }; // 对
每一个类都直接或间接的继承于Object超类。
1.2 super关键字
super关键字的用法和this关键字用法相似。this代表本类对象引用,super代表父类对象引用。
关键字 | 访问成员变量 | 访问构造方法 | 方法成员方法 |
this | this. 成员变量 | this(……) | this. 成员方法(……) |
访问本类成员变量 | 访问本类构造方法 | 访问本类成员方法 | |
super | super. 成员变量 | super(……) | super. 成员方法(……) |
访问父类成员变量 | 访问父类构造方法 | 访问本类成员方法 |
就近原则:
现在局部位置本来成员位置找this,父类成员位置找super,逐级往上如果没找到就报错。
- 带参构造
子类中所有的构造方法默认都会访问父类中无参构造方法。
每个子类构造方法第一行语句,默认都是super();
1.3 重写Override
什么是方法重写:当父类的方法不满足子类现在的需求时,子类可以重写一个和父类一模一样的方法。
规则:
- 修饰词:子类方法的权限不能比父类小(子类>=父类),返回值类型子类要<=父类。
- 返回值:8种基本数据类型必须保持一致
- 签名(方法名和参数列表):子类和父类的签名必须保持一致,
- 子类不能重写父类的静态方法。
什么时候用:
当子类需要父类的功能时,而功能主体子类有自己特定的内容时,可以重写父类中的方法。
这样既沿袭了父类的功能,又定义了子类特有的内容。
例:
//手机类
public class Phone {
public void call(String name){
System.out.println("给"+ name +"打电话");
}
}
//新手机
public class NewPhone extends Phone {
@Override //重写注解符
public void call(String name) {
System.out.println("开启视频功能");
System.out.println("给" + name + "打电话");
super.call(name);
}
}
这里public尽量访问权限一致,要么父类private,子类public。
//测试类
public class PhoneTest {
public static void main(String[] args) {
//创建对象,调用方法
Phone p = new Phone();
p.call("手机");
System.out.println("--------");
NewPhone np = new NewPhone();
np.call("新手机");
}
}
-
this和super的总结
使用this的3种情况:
- 在本类的成员方法中,可以访问本类的成员变量(外部类)。
- 在本类的成员方法中,访问本类的其他成员方法。
- 在本类的构造方法中可以访问本类的其他构造方法(有参无参)。
注意:构造方法是不可以自己调用自己的。
使用super的3种情况:
- 在子类的成员方法中,访问父类的成员变量(外部类,父类子类都在同个测试类里)。
- 在子类的成员方法中,访问父类的成员方法(Override重写)。
- 在子类的构造方法中,访问父类的构造方法(super的无餐有餐)。
二、类的多态
2.1 概述
类的多态是面向对象中的第三大特性,是指同一个对象,在不同时刻表现出来的不同形态。表现为:对象多态,行为多态。
多态的前提:
- 有继承 / 接口实现关系
- 有方法重写
- 有父类引用指向子类对象。
格式:
父类 对象名 = new 子类 ();
public static void 方法名 (父类. 对象名){
对象名( );
}
多态的好处:
- 使用父类型作为参数,可以接受所有子类对象,体现了多态的扩展性与便利。
- 多态的存在大大提高了程序的复用性和可维护性。减少了代码的冗余,增强程序的可读性和可扩展性。
2.2 多态中的转型
- 向上转型
从子到父,父类引用指向子类(接口引用指向子类)
- 向下转型 instanceof
从父到子,父类引用转为子类对象
2.2.1 向上转型
其实态本身就是向上转型的过程,前面说的 “父类 对象名 = new 子类 ();”都是向上转型。
例:
//职工类
public abstract class Emp {
String name;
int age;
double sal;
//添加方法
public void clockUp(){
System.out.println("上班打卡:");
}
public void clockDown() {
System.out.println("下班打卡:");
}
//添加个抽象方法
public abstract void work();
}
//讲师的接口1-顾问
public interface Question {
public abstract void answer(); //解决企业问题
public abstract void training(); //培训企业员工
}
//讲师的接口2-成为作者
public interface Author {
public abstract void edit ();/* 编辑文稿 */
}
//讲师类
public class Teacher extends Emp implements Question,Author{ //讲师类去实现接口
@Override
public void work() {
System.out.println("讲师授课");
}
@Override
public void answer() {
System.out.println("解决企业问题");
}
@Override
public void training() {
System.out.println("培训企业员工");
}
@Override
public void edit() {
System.out.println("编辑文稿");
}
//这里也直接可以创建主函数
public static void main(String[] args) {
Teacher t = new Teacher();
t.answer();
t.edit();
t.training();
t.work();
System.out.println("---------");
// 用向上转型的方式 (老师的父类是员工,所以使用员工类型也是可以老师对象的)
Emp e = new Teacher();
e.clockUp();
e.clockDown();
// 使用向上造型方式来调方法或者属性,注意一定得是父类拥有的,而不能是子类拥有的
//向上转型还可以是接口
Question q = new Teacher();
q.answer();
q.training();
Author a = new Teacher();
a.edit();
}
}
2.2.2 向下转型
多态的弊端:
不能调用子类的特有功能,如在Teacher类中加其他方法,父类中没有这个方法,则就不会被调用,会报错!
解决:变回子类类型(类似强转)
Emp e = new Teacher();
e.work(); //父类中的方法
Teacher t = (Teacher) e;
t.eat();
例:
public abstract class Animal {
//吃
abstract void eat();
}
public class Dog extends Animal{
@Override
void eat() {
System.out.println("狗吃骨头");
}
void LookWork(){ //加一个子类特有的方法
System.out.println("看大门");
}
}
public class Cat extends Animal{
@Override
void eat() {
System.out.println("猫吃鱼");
}
void CatchWork(){ //加一个子类特有的方法
System.out.println("抓老鼠");
}
}
public class Demo {
public static void main(String[] args) {
Demo demo = new Demo();
Cat cat = new Cat();
Dog dog = new Dog();
//用向上造型方法
Animal animal1 = new Cat();
Animal animal2 = new Dog();
demo.showAnimal(animal1);
demo.showAnimal(animal2);
// //调用子类特有方法,,发现报错调用不了
// animal1.CatchWork();
/*
*向下转型(强转)
* Animal1 向下转型
* */
Cat c = (Cat) animal1;
c.CatchWork();
// Cat c2 = (Cat) animal2;
// c2.CatchWork(); //这里报错
/*
原因:TODO 上一条强转是因为animal1,本质是cat对象,而强转恰好也是cat类型,所以没报错,
TODO 而animal2本质是dog对象,不能把dog强转为cat(不可以让Dog去执行Cat的动作!!),所以报错了
*/
/*
解决方案:在进行类型转换前,做一次有必要的类型判断,
TODO 关键字:instanceof
格式: 变量名称 instanceof 数据类型
这是一个Boolean类型的表达式,如果变量符合后面要转换的类型,则返回true,否则false,常用if判断
*/
if(animal1 instanceof Cat){ //如果animal2是猫类型,则转换为猫,干猫的事情
Cat c1 = (Cat) animal2;
c1.CatchWork();
}else if (animal2 instanceof Dog){ //如果animal2是狗类型,则转换为狗,干狗的事情
Dog d1 = (Dog) animal2;
d1.LookWork();
}
if(animal1 instanceof Cat){ //如果animal2是猫类型,则转换为猫,干猫的事情
Cat c1 = (Cat) animal1;
c1.CatchWork();
}else if (animal1 instanceof Dog){ //如果animal2是狗类型,则转换为狗,干狗的事情
Dog d1 = (Dog) animal1;
d1.LookWork();
}
}
void showAnimal(Animal animal){
}
}
注:向下转型是通过强制类型转换实现的,它可能导致运行时异常,可能会出现数据溢出,从而丢失精度。
解决方案:
在进行类型转换前,做一次有必要的类型判断,
关键字:instanceof
格式: 变量名称 instanceof 数据类型
(这是一个Boolean类型的表达式,如果变量符合后面要转换的类型,则返回true,否则false,常用if判断)
三、抽象类与接口
3.1 抽象类
概述:在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类就得定义为抽象类。
抽象方法:在父类中不能确定具体的方法体,该方法就可以定义为抽象方法。
抽象类:如果一个类中存在抽象方法,该类就必须为抽象类。
- 关键字 abstract:
抽象类定义格式:public abstract class 类名 { }
抽象方法定义格式;public abstract 返回值类型 方法名(参数列表);(注意:没有{}直接;结束)
- 抽象类的注意事项,特点:
- 抽象类中不一定有抽象方法,但有抽象方法的类一定是抽象类
- 抽象类不能创建对象,抽象类和方法可以有构造方法,怎么创建对象呢?参照多态,子类对象实例化
- 类本该有的成员(成员变量,方法,构造器)抽象类都可以有
- 抽象类最主要的特点:不能创建对象,仅作为一种特殊的父类,让子类继承并实现
- 抽象类的子类,要么重写抽象类中的所有方法,要么让子类也变抽象类
3.2 接口
Java中的接口更多体现的是对行为的抽象。接口可以被类或其他接口实现,实现接口的类必须提供接口中所有抽象方法的实现。
- 关键字:interface
public interface 接口名 { } (接口不能创建对象,即不能实例化)
- 关键字:implements
public class 类名 implements 接口名 { }
接口的子类(也称实现类):
要么重写接口中的所有抽象方法,要么让子类也变抽象类
注:
- 接口和类还可以有实现关系,可以单实现,也可以多实现
public class 类名 implements 接口1,接口2 { }
2.实现类可以继承父类时同时实现多个接口
public class 类名 extends 父类 implements 接口1,接口2 { }
3.3 接口的实现过程
1、接口是没有静态代码块或者构造方法的
如先定义一个接口:
public interface Interface01{
static{ }
public Interface01{ }
}
// 报错,接口是不能含有静态代码块或者构造方法的
2、一个类的直接父类是唯一的,但一个类可以有多个接口,是先继承后实现的。
public class Implements extends Object implements Implements01, Implements02, Implements03{
3、如果实现类的多个接口当中,存在重复的抽象方法,那么只需要重写一次即可。
@Override
public void method01(){
}
}
接口1中:
public interface Interface01{
public abstract void method01();
}
接口2中:
public interface Interface02{
public abstract void method01();
}
4、如果实现类没有覆盖所在的接口中的所有抽象方法,那么实现类必须是一个抽象类。
接口1中:增加了两个抽象方法,但不重写
public abstract void method02();
public abstract void method03();
在实现类直接加abstract即可:
public abstract class Implements extends Object implements Implements01, Implements02, Implements03{}
5、如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的类进行重写。
接口1中增加:
default void method04();
在实现类就要重写method01,method02,method03,method04所有方法,并去掉 abstract ,重写method04,default会变public,因为default不能被重写。
6、一个类如果直接父类当中的方法和接口中默认的方法产生了冲突,要优先使用父类中的方法。
四、类的高级特性
4.1 final 修饰词
final(最终态)最终的意思,修饰成员方法,成员变量、类,也称常量。
- 规则:
- 修饰方法:表明该方法是最终方法,不能被重写。
- 修饰变量:表明该变量是常量,不能再次赋值
- 修饰类:表明该类是最终类,不能被继承。且final和abstract不能同时出现在同一句代码中。
- final修饰局部变量:
- 变量是基本类型:final修饰基本类型的数据值不能发生改变。
- 变量是引用类型:final修饰引用类型,地址值不能发生改变,但是地址里内容可以发生改变。
public class Fu{
public final void method(){
System.out.println("Fu method");
}
}
public class Zi extends Fu{
@Override
public void method(){
//报错,被final修饰不能重写
}
}
//子类可以写成:
public class Zi extends Fu{
public final int age = 22;
public void show(){
System.out.println(age);
}
}
//Fu类写了final,子类就不能被继承了,会报错
public final class Fu{
}
4.2 static 修饰词
static 静态,是Java中的一个修饰符,可以修饰成员方法,成员变量。
- 被static修饰的成员变量,叫静态变量。
特点:被该类所有对象共享,每个对象都有。
调用方式:类名调用,对象名调用
- 被static修饰的成员方法,叫静态方法。
特点:多用在测试类和工具类中。Javabean类中很少会用
public class student {
private String name;
private int age;
private String gender;
//加一个老师对象
public static String teacherName;
//static静态就是可以一次性赋值
public void show(){
System.out.println(name+age+gender+teacherName);
}
}
public class studenttest {
public static void main(String[] args) {
student.teacherName = "王老师";
student s1 = new student();
s1.setName("张三");
s1.setAge(23);
s1.setGender("男");
}
static 访问特点:
- 静态成员方法只能访问静态成员。
- 非静态方法可以访问所有
- 方法中是没有this关键字的
- 静态方法只能继承,不能重写。
4.3 代码块
使用 { }定义的一段代码称为代码块,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象调用
代码块分为一下4种:
局部代码块(普通代码块)
构造代码块(实例代码块)
静态代码块
同步代码块
1、局部代码块(普通代码块)
- 位置:方法中定义
- 作用:限定变量的生命周期,及早释放,提高内存利用率
public static void main(String[] args) {
{
System.out.println("这是一个普通代码块");
}}
2、构造代码块(实例代码块)
- 位置:类中 方法外定义
- 特点:每次构造方法执行的时,都会执行该代码块中的代码,并且在构造方法执行前执行
- 作用:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性
class Student {
public String name;
public double score;
public int age;
public Student (String name,int age,String gender,) {
this.name = name;
this.age = age;
this.gender = gender;
}
{
this.name = "张三";
System.out.println("构造代码块");
}
public void goname(Student this) {
System.out.println(this);
}
}
3、静态代码块
- 位置:类中方法外定义
- 特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
- 作用:在类加载的时候做一些数据初始化的操作
public class Demo {
public static void main(String[] args) {
System.out.println("putong");
}
}
class Static {
public static int a = 10;//静态属性
//静态代码块
static {
System.out.println("静态代码块");
}
4.4 匿名对象
- 概述:
- 匿名对象的使用,有如下几种方式:
- 创建匿名对象直接使用,没有变量名,只能使用一次。
- 匿名对象可以作为方法接收的参数、方法返回值使用
例:
public class Person {
public void show() {
System.out.println("------");
}
}
创建普通对象:
Person p = new Person();
创建匿名对象:
new Person();
4.5 内部类
4.5.1 成员内部类
- 成员内部类定义在外部类的成员位置,且没有使用static修饰。
- 如同成员一样,也可使用任意访问修饰符
- 成员内部类可以直接访问外部类的所有成员。
4.5.2 静态内部类
- 静态内部类不需要依赖于外部类,也就是说,可单独创建静态内部类对象,不需要通过外部类对象来创建。
- 静态内部类是定义在外部类的成员位置,并且有static修饰。
- 可直接访问外部类的所有静态成员,包括私有的,但不能直接访问非静态成员。(但可通过外部类对象访问非静态成员)。
- 如同其他成员一样,也可添加任意访问修饰符。
- 外部类名.内部类名 对象名 = new 外部类名.内部类对象 ();
范例: Outer.Inner in = new Outer.Inner();
访问方式:
- 直接访问外部类的所有静态成员(包括私有),不能直接访问非静态成员
- 创建内部类对象,再访问静态内部类的所有成员(包括私有)。
4.5.3 局部内部类
- 局部内部类是定义在外部类的局部位置,比如方法、代码块中,并且有类名。
- 可直接访问外部类的所有成员,包括私有的。
- 局部内部类只能访问final的局部变量,(若访问的局部变量没加final修饰符,则编译器会自动加上)。
public class Class {
private int out;
public void test(){
final int a = 2;
//局部内部类
class B{
public void testk(){
//局部内部类访问局部变量k,若局部变量k不声明final,则编译器会默认加上final修饰符
System.out.println(k);
}
}
B b = new B();
b.testk();
}
}
4.5.4 匿名内部类
- 匿名内部类定义在外部类的局部位置,没有类名。
- 匿名内部类是唯一一种没有构造器的类。
- 匿名内部类只能实例化一次对象。
- 匿名内部类只能访问final的局部变量,(若访问的局部变量没加final修饰符,则编译器也会自动加上)。
- 前提:需要存在一个接口或类
//若是创建类的匿名内部类对象,则参数列表就是类的构造器方法的参数列表
new 类或接口(参数列表){
类体
};
五、异常
5.1 认识异常
异常就是代表程序中的出现的问题,最终会导致JVM(Java虚拟机)的非正常停止。
在Java中,异常本身就是一个类,产生异常就是创建异常对象并抛出了一个异常对象。
1.Java中的所有不正常类都继承于Throwable(Java中所有错误或异常的超类)。Throwable主要包括两个大类,一个是Error类,另一个是Exception类;
2.代表的系统级别错误(属于严重问题),也就是说不是程序编译运行的错误,而是虚拟机和线程死锁的问题。
3.Exception叫异常,他代表是我们程序可能出现的问题,它包括:
- 运行时异常:RuntimeException及其子类,编译阶段不会出现错误提醒,运行时出现的异常。
- 编译时异常:编译阶段时会出现错误提醒的。
4.抛出异常(throws)
- 在方法上使用throws关键字,可以将方法内部出现的异常抛出去给调用者处理。
方法 throws 异常1,异常2,异常3...{
......
}
5.捕获异常(try...catch)
- 直接捕获程序出现的异常
try {
// 监视可能出现异常的代码
}catch(异常类型1 变量){
// 处理异常
}catch(异常类型2 变量){
// 处理异常
}...
5.2 自定义异常
- Java无法定义出所以会出现的异常,在编程时遇到某种问题,想通过异常表示,以便用异常来管理该问题,那就需要用户自己定义异常了。
5.3 Java中常见的异常
NullPointerException
空指针异常,最常见的一个异常类。简言之,调用了未经初始化的对象或者是不存在的对象,就会产生该异常。
ArithmeticException
算术运算异常,程序中出现了除数为0这样的运算,就会出现这样的异常。
此外还有:
ArrayIndexOutOfBoundsException
数组下标越界异常,跟数组打交道时,需要注意一下这个异常。
FileNotFoundException
文件未找到异常,一般是要读或者写的文件,找不到,导致该异常。
SQLException
操作数据库异常,它是Checked Exception(检查异常);
六、集合
集合的概念
- 概念:对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能。
- 和数组区别:
- 数组长度固定,集合长度不固定
- 数组可以存储基本类型和引用类型,集合只能存储引用类型
6.1 Collection集合
6.1.1 概述:
- 是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
- JDK不提供此接口的任何直接实现,它提供更具体的子接口(如Set和List)实现
- 创建Collection集合的对象
- 多态的方式
- 具体的实现类ArrayList
//创建Collection集合的对象
//多态的方式
//Arraylist()
public class CollectionDemo01 {
public static void main(String[] args) {
//创建Collection集合对象
Collection<String> c= new Arraylist<String>();
// 添加元素:boolean add (E e)
c.add("hello");
c.add("wor1d");
c.add("java");
//输出集合对象
System.out.println(c);
}
}
6.1.2 集合常用方法
方法名 | 说明 |
boolean add(E e) | 添加元素 |
boolean remove(Object o) | 从集合中移除指定的元素 |
void clear() | 清空集合中的元素 |
boolean contains(Object o) | 判断集合中是否存在指定元素 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中元素的个数 |
6.1.3 集合的遍历
Iterator:迭代器,集合的专用遍历方式
- Iterator<E>iterator() :返回此集合中元素的迭代器,通过集合的iterator()方法得到
- 迭代器是通过集合的iterator()方法得到的,所以我们说它是依赖于集合而存在的
Iterator中的常用方法
- E next():返回迭代中的下一个元素
- boolean hasNext():如果迭代具有更多务元素,则返回true
6.2 List集合
6.2.1 List集合的概述和特点
List集合概述
- 有序集合(也称为序列),用户可以精确控制列表中每个元素的插入位置。用户可以通过整数索引访问元素,并捜索列表中的元素
- 与Set集合同,列表通常允许重复的元素
List集合特点
- 有序:存储和取出的元素顺序一致
- 可重复:存储的元素可以重复
public class ListDemoe1 {
public static void main(String[] args) {
//创建集合对象
List<String> list = nаv Arraylist<String>();
//添加元素
list.add("hello");
list.add("world");
list.add("java");
//输出集合对象
// Systen.out.println(list);
//迭代器的方式遍历
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s= it.next();
System.out.println(s);
}
}
}
6.2.2 List集合的特有方法
方法名 | 说明 |
void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index,Eelement) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
6.2.3 增强for循环
增强for:简化数组和Collection集合的遍历
- 实现Iterable接口的类允许其对象成为增强型for语句的目标
- 它是JDK5之后出现的,其内部原理是一个lterator迭代器
增强for的格式
- 格式:
for(元素数据类型 变量名 : 数组或者Collection集合){
//在此处使用变量即可,该变量就是元素
}
- 范例:
int [] arr = {1,2,3,4,5};
for(inti:arr){
System.out.printIn(i);}
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
for(int i : arr) {
System.out.println(i);
}
System.out.println("--------");
String[] strArray = ("hello","world","java"};
for(String s: strArray) {
System.out.println(s);
}
Systen.out.println("--------");
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
for(String s: list) {
Systen.out.println(s);
}
System.out.println("--------");
//内部原理是一个Iterator迭代器
for(String s : list) {
if(s.equals("world")) {
list.add("javaee");
}
}
}
6.3 其他
ArrayList实现类
泛型
Set接口与实现类:
HashSet、TreeMap实现类
Map集合:
概述:Interface Map <K,V> (键值对)
K:键的类型 V:值的类型