继承就是在已经存在的类的基础上进行扩展,从而产生新的类,支持了层次结构分类的概念。已经存在的类称为父类、超类或基类,而新产生的类称为子类或派生类。多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。多个类可以称为子类,单独这个类称为父类或者超类。
1、通过 extends 关键字让类与类之间产生继承关系(1)继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。(2)继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。(3)继承是is-a 的相互关系2、在 Java 中父类所拥有的一切,子类都可以继承(1)私有属性是否可被继承--- 两种答案①第一种答案:子类对象确实拥有父类对象中所有的属性和方法,但是父类对象中的私有属性和方法,子类是无法访问到的,只是拥有,但不能使用。就像有些东西你可能拥有,但是你并不能使用。所以子类对象是绝对大于父类对象的,所谓的子类对象只能继承父类非私有的属性及方法的说法是错误的。可以继承,只是无法访问到而已。②第二种答案:一个类的成员就是指在这个类中所声明的属性和方法,再加上从其父类继承而来的属性和方法。也就是说,子类是不能继承父类的私有成员的。(2)子类除了拥有父类的属性和方法(拥有父类的所有成员,但是注意构造器和析构器不是成员),也可以创建自己的特性(3)可以减少代码,而且易于维护
建议的使用场景:把通用操作和方法放在父类中,将特殊的方法定义在子类中。好处在于:1、避免代码重复。2、避免了人为因素导致的不一致性
1 、 Java 中不支持多重继承。 Java 中要求任何的子类只能有一个直系的双亲类原因: (1)因为多继承容易出现问题。两个父类中有相同的方法,子类到底要执行哪一个是不确定的(2)如果定义类但是没有extends,则意味着默认父类为java.lang.Object。这也就是说Java中的任意类都是Object的子类2、 如果定义类但是没有 extends ,则意味着默认父类为 java.lang.Object 。这也就是说 Java 中的任意类都 是 Object 的子类3 、可以在子类中进行覆盖定义父类中的成员方法和成员属性public class A {protected long id ;}public class B extends A {protected String id ;}
java支持多层继承(继承体系):java中的所有类都直接或间接的集成与java.lang.Object类
C继承B,B继承A,就会出现继承体系
多层继承出现的继承体系中,通常看父类的功能,了解该体系的基本功能,建立子类对象,即可使用该体系功能
继承的出现提高了代码的复用性,让类与类之间产生了关系,提供了多态的前提
1、将所有子类的共同属性放入父类,实现代码共享,避免重复,提高开发效率
2、可以使得修改扩展继承而来的实现比较简单
1、父类变,子类就必须变
2、继承破坏了封装,对于父类而言,它的实现细节与子类来说都是透明的
3、继承是一种强耦合关系
package com.yan2;
public class Test3 {
public static void main(String[] args) {
A3 aa = new A3();
// 默认输出格式为[com.yan2.A3@7d6f77cc],其实就是调用了Object中所定义的toString方法
System.out.println(aa);
/*
* println打印输入任意对象类型时,实际上会调用String类中定义的valueOf方法,将对象转换为String进行输出 String s =
* String.valueOf(x);
*
* String中的valueOf针对null进行了字符串话处理,如果是非空对象则调用对象中的toString方法 public static String
* valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); }
*
* 所有的Java对象都直接或者间接的继承于Object类,所以当前类中即使没有定义toString方法,也会从
* Object类中继承得到toString方法。Object类中定义的toString方法为【当前对象所属类的全名称@16进制hash值字符串】
* public String toString() { return getClass().getName() + "@" +
* Integer.toHexString(hashCode()); }
*
* 哈希值是一个和当前对象存储位置相关的整型值
*/
}
}
//父类型
//当定义一个类没有extends任何类时,java默认继承java.lang.Object类
//Java中的所有类都直接或者间接的继承于Object
class A3 {
}
class A31 {
}
//子类型
/*
* Java中采用的是单根继承体系,所有的类只能有一个双亲类
*/
class B3 extends A3
//,A31
{
}
意思是最终的、不变的
final修饰变量时,变量必须被初始化,并且不能被修改。初始化可以定义final变量时直接初始化或者在构造函数中初始化
final修饰方法则该方法不能被子类重写
final修饰一个类,则该类不能被继承
package com.yan6;
public class Test1 {
}
//final修饰一个类,则该类不能被继承
final class A1 {
}
//class B1 extends A1{}
//String是final类型的类,所以不能被继承
//class C1 extends String{}
//class D1 extends StringBuffer{}
//class D2 extends Integer{}
//特殊的点
class E1 {
private E1() {
}
}
//E1不能被继承的原因是:E1的所有构造器是private的
//class F1 extends E1{}
表示字符串的3种类型String、StringBuffer、StringBuilder都是final类型的类,所以都不允许继承
package com.yan3;
/*
* java针对字符串类型提供了3种类:String StringBuilder和StringBuffer
*
*/
public class Test2 {
public static void main(String[] args) {
String s1 = "abc";
// String s2 = new String();// new String("abc");
System.out.println(s1.length());// 获取字符串中的个数,注意不区分大小写
System.out.println(s1.charAt(0));// 获取指定下标位置的字符
System.out.println(s1.indexOf("b"));// 从左向右查找指定参数字符串对应的起始下标位置
System.out.println(s1.lastIndexOf("b"));// 从右向左查找指定参数字符串对应的起始下标位置
System.out.println(s1.substring(0, 2));// 指定下标参数区间的子字符串,含左不含右
// 字符串拼接
s1 = "aa" + s1 + "!";
System.out.println(s1 + "\n");
StringBuilder ss1 = new StringBuilder("abc");// new StringBuilder();
System.out.println(ss1);
System.out.println(ss1.length());// 获取字符串中的个数,注意不区分大小写
System.out.println(ss1.charAt(0));// 获取指定下标位置的字符
System.out.println(ss1.indexOf("b"));// 从左向右查找指定参数字符串对应的起始下标位置
System.out.println(ss1.lastIndexOf("b"));// 从右向左查找指定参数字符串对应的起始下标位置
System.out.println(ss1.substring(0, 2));// 指定下标参数区间的子字符串,含左不含右
ss1.insert(0, "aaa").append("!");// insert在指定位置插入字符串,append在字符串末尾追加内容
System.out.println("ss1:" + ss1);
ss1.delete(1, 3);// 删除指定区间的内容
System.out.println(ss1);
ss1.deleteCharAt(ss1.length() - 1);// 删除指定下标位置上的一个字符
System.out.println(ss1);
ss1.replace(1, 2, "11ashjfkjs22");// 将指定区间上的字符串转换为参数3字符串
System.out.println(ss1);
// 反转字符串
StringBuilder ss11 = ss1.reverse();
System.out.println(ss11 + "\n");
StringBuffer ss2 = new StringBuffer("bbbbb");// new StringBuffer();
System.out.println(ss2);
System.out.println(ss2.length());// 获取字符串中的个数,注意不区分大小写
System.out.println(ss2.charAt(0));// 获取指定下标位置的字符
System.out.println(ss2.indexOf("b"));// 从左向右查找指定参数字符串对应的起始下标位置
System.out.println(ss2.lastIndexOf("b"));// 从右向左查找指定参数字符串对应的起始下标位置
System.out.println(ss2.substring(0, 2));// 指定下标参数区间的子字符串,含左不含右
ss2.insert(0, "aa").append("!");
System.out.println("ss2:" + ss2);
/*
* 如果需要使用字符串常量或者修改次数较少,可以使用String 如果需要频繁修改可以考虑使用StringBuilder或者StringBuffer
* 如果需要考虑线程安全问题则使用StringBuffer;如果没有线程安全问题则直接使用StringBuilder,临时变量
*
*/
}
}
1、final 属性上可以声明的同时直接赋值或者在构造器中赋值2、final 临时变量,可以声明的同时赋值或者在第一次使用之前进行赋值注意:final 类型的变量一旦赋值则不允许修改,但是如果是复杂类型是不允许修改地址,但 是可以修改属性3、final 方法表示这个方法不允许在子类中重新定义(覆盖 \ 重写)4、final 类表示这个类不允许被继承
private私有构造器
模式:由专家总结出来的在某种情况下解决某类问题的最佳解决方案,是思想、是知识,是一种抽象的内容意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。主要解决:一个全局使用的类频繁地创建与销毁。何时使用:当您想控制实例数目,节省系统资源的时候。单例模式有多种写法,最常见的是懒汉模式和饿汉模式
package com.yan6;
//
public class Singleton {
//饿汉模式
// 保证在当前类以外无法创建对象
private Singleton() {
}
private final static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
class A {
public static void main(String[] args) {
// Singleton s1=new Singleton.getInstance();
}
}