Java的继承特性
什么是继承:
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
为什么要使用继承:
在不同的类中也可能会有共同的特征和动作,可以把这些共同的特征和动作放在一个类中,让其它类共享。
因此可以定义一个通用类,然后将其扩展为其它多个特定类,这些特定类继承通用类中的特征和动作。
继承是 Java 中实现软件重用的重要手段,避免重复,易于维护,易于理解。
Java中怎么继承:
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:
类的继承格式
class 父类 {}class 子类 extends 父类 {}
继承的特性
- 子类拥有父类非private的属性,方法。
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
Java的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如A类继承B类,B类继承C类,所以按照关系就是C类是B类的父类,B类是A类的父类,这是java继承区别于C++继承的一个特性。
提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系)。
继承关键字(extends)
继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang 包中,所以不需要 import)祖先类。
在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。
super关键字:可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
this关键字:指向自己的引用。
final关键字:关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写:
Object类
Object类在JAVA里面是一个比较特殊的类,JAVA只支持单继承,子类只能从一个父类来继承,如果父类又是从另外一个父类继承过来,那他也只能有一个父类,父类再有父类,那也只能有一个,JAVA为了组织这个类组织得比较方便,它提供了一个最根上的类,相当于所有的类都是从这个类继承,这个类就叫Object。所以Object类是所有JAVA类的根基类,是所有JAVA类的老祖宗。所有的类,不管是谁,都是从它继承下来的。
方法的重写
什么是重写:
从字面上看,重写就是 重新写一遍的意思。其实就是在子类中把父类本身有的方法重新写一遍。子类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中的某个方法,所以在方法名,参数列表,返回类型(除过子类中方法的返回值是父类中方法返回值的子类时)都相同的情况下, 对方法体进行修改或重写,这就是重写。但要注意子类函数的访问修饰权限不能少于父类的。
public class Father {
public static void main(String[] args) {
// TODO Auto-generated method stub
Son s = new Son();
s.sayHello();
}
public void sayHello() {
System.out.println("Hello");
}
}
class Son extends Father{
@Override
public void sayHello() {
// TODO Auto-generated method stub
System.out.println("hello by ");
}
}
总结:
- 发生在父类与子类之间
- 方法名,参数列表,返回类型(除过子类中方法的返回类型是父类中返回类型的子类)必须相同
- 访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
- 重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常
Java面向对象的多态性
public class Wine {
public void fun1(){
System.out.println("Wine 的Fun.....");
fun2();
}
public void fun2(){
System.out.println("Wine 的Fun2...");
}
}
public class JNC extends Wine{
/**
* @desc 子类重载父类方法
* 父类中不存在该方法,向上转型后,父类是不能引用该方法的
* @param a
* @return void
*/
public void fun1(String a){
System.out.println("JNC 的 Fun1...");
fun2();
}
/**
* 子类重写父类方法
* 指向子类的父类引用调用fun2时,必定是调用该方法
*/
public void fun2(){
System.out.println("JNC 的Fun2...");
}
}
public class Test {
public static void main(String[] args) {
Wine a = new JNC();
a.fun1();
}
}
//运行结果
//-------------------------------------------------
//Output:
//Wine 的Fun.....
//JNC 的Fun2...
指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法
instanceof操作符
向下转型
public interface A {
}
public class B implements A{
}
public class C extends B{
}
public class InstanceofTest3 {
public static void main(String[] args) {
A a = null;
B b = null;
boolean result;
result = a instanceof A;
System.out.println(result); // 结果:false null用instanceof跟任何类型比较时都是false
result = b instanceof B;
System.out.println(result); // 结果:false null用instanceof跟任何类型比较时都是false
a = new B();
b = new B();
result = a instanceof A;
System.out.println(result); // 结果:true a是接口A的实例对象引用指向子类类B,类B实现了接口A,所以属于同一个继承树分支
result = a instanceof B;
System.out.println(result); // 结果:true a是接口A的实例对象引用指向子类类B,类B实现了接口A,所以属于同一个继承树分支
result = b instanceof A;
System.out.println(result);// 结果:true b是类B的实例对象,类B实现了接口A,所以属于同一个继承树分支
result = b instanceof B;
System.out.println(result);// 结果:true b是类B的实例对象,类B实现了接口A,所以属于同一个继承树分支
B b2 = new C();
result = b2 instanceof A;
System.out.println(result); // 结果:true b2是父类B引用指向子类C,类B实现了接口A,所以属于同一个继承树分支
result = b2 instanceof B;
System.out.println(result); // 结果:true b2是父类B引用指向子类C,所以属于同一个继承树分支
result = b2 instanceof C;
System.out.println(result); // 结果:true b2是父类B引用指向子类C,所以属于同一个继承树分支
}
}
instanceof是Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false。
equals方法(比较)
String a="a";
String b="b";
if(a.equals(b)){//判断引用值是否相等,相等即返回true ,条件为真继续往下走,反之结束。
}
判断类型是否匹配,类型相同,长度相等,逐个比较字符是否一样,完全符合,则返回ture,一旦不对,返回false;
equals和==的区别
equals在Object中定义时
public boolean equals(Object obj) {
return (this == obj);
}
String则对父类Object的equals方法进行了重写
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n– != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
总结:
- equals的作用:用于判断两个变量是否是对同一个对象的引用,即堆中的内容是否相同,返回值为布尔类型
- 对象不同,内容相同 用==比较返回的是false(比较地址),equals返回true(比较内容)
String s1 = new String("java");
String s2 = new String("java");
System.out.println(s1==s2); //false
System.out.println(s1.equals(s2)); //true
Object类的toString()方法
@Test 单段代码测试
import org.junit.Test;
public class TestMethods {
@Test
public void test() {
System.out.println(“hello world”);
}
}
1:首先需要导入import org.junit.test这个jar包,@Test注解要写在你要测试的方法上面
2:然后点击–运行方式,再点击Junit测试,就可以了。
test()方法里面写你需要测试的方法就可以了
—TestMethods这个类不用new,就可以运行。是因为它是通过org.junit.Test中的API中的类反射生成的,然后调用用@Test注解的方法,有几个@Test注解,就运行几个test方法。
包装类
什么是自动装箱和自动拆箱:
自动装箱和自动拆箱是JDK5.0出现的新特色,可以分别对应理解为基本数据类型到包装类、包装类到基本数据类型的转换不需要显示转换。
public class AutoChaiZhuang{
public static void main(String[] args){
//自动装箱
int num = 9;
Integer in = num;
//自动拆箱
int num1 = in;
}
}
byte -- Byte
short -- Short
int -- Integer
long -- Long
float -- Float
double -- Double
boolean -- Boolean
char -- Character
1.基本数据类型转包装类
// 基本数据类型转包装类,调用相应包装类的构造器即可
public class JiBen2BaoZhuang{
public static void main(String[] args){
//基本数据类型参数构造器
int num = 9;
Integer inum = new Integer(num);
//字符串构造器
Integer inum2 = new Integer("9")
}
}
2.包装类转基本
//包赚类转基本数据类型,调用该包装类的XXXValue()
public class Baozhuang2JiBen{
public static void main(String[] args){
//int--Integer
Integer in1 = new Integer(9);
int num1 = in1.intValue();
//float-- Fliat
Float f1 = new Float(9.9);
float num2 = f1.floatValue();
}
}
3.String转基本数据类型/包装类
//String转基本数据类型/包装类,调用相应包装类的parseXxx(String str)
public class String2BaoJi{
public static void main(String[] args){
String str = "999";
//String 转 int
int num = Integer.parseInt(str)
boolean b = Boolean.parseBoolean(str)//当str!=“true”,不区分大小写,皆为false
}
}
4.基本数据类型/包装类转String
//基本数据类型/包装类转String,调用String重载的ValueOf()
public class BaoJi2String{
public static void main(String[] args){
int num = 9;
// 方式1 利用数据类型的自动提升
String str1 = num+"";
// 方式2 调用ValueOf()
String str2 = String.valueOf(num);
}
}
static关键字(静态)
静态变量和静态代码块在类初次加载时会被初始化,且只能被初始化一次。(静态代码块不能写在方法体里面)
java中static关键字修饰的成员变量和方法是静态变量和方法,使用规则如下:
-
static方法只能调用static方法或static变量,不能调用非static方法或非static变量,换句话说就是,静态方法只能调用静态方法或静态变量,不能调用非静态方法或非静态变量。注:在静态方法中可以通过创建对象,通过创建的对象调用该对象的非静态方法。
-
static方法中不能使用this或super关键字。
-
static不能用于修饰局部变量,另外构造器不是静态方法,因为构造器里可以引用this和super关键字。
static的用法
- 修饰成员变量:类实例存放在堆中,成员变量属于类实例,也存放在堆中。使用static修饰后,成员变量便属于类,而不属于某个具体的对象,存放位置发生改变存放在方法区中。
- 修饰成员方法:成员方法属于类实例,但是相同类的不同实例共用同一个方法,方法都存在与方法区,使用static修饰后不会改变方法存放位置,但是会改变归属
- 修饰代码块:static块中的代码将在类加载的时候进行执行,多个static块按照顺序执行
- 静态内部类:在构造者模式中使用较多,其他的用法暂时没有思考,不过把静态内部类与构造者模式关联起来,方便记忆,而且不容易和其他的内部类搞混
/**
* @author cade
* 需要注意作用域
*/
public class Pizza {
private String name;
private String price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public static Builder newBuilder() {
return new Builder();
}
//私有空构造器
private Pizza() {
}
//带参构造器为Builder使用
private Pizza(Builder builder) {
this.name = builder.name;
this.price = builder.price;
}
public static final class Builder {
private String name;
private String price;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder price(String price) {
this.price = price;
return this;
}
public Pizza build() {
return new Pizza(this);
}
}
public static void main(String[] args) {
Pizza pizza = Pizza.newBuilder().name("chicken cheese").build();
System.out.println(pizza.getName());
}
}
单例设计模式