10.13动手动脑
public Grandparent() {
System.out.println("GrandParent Created.");
}
public Grandparent(String string) {
System.out.println("GrandParent Created.String:" + string);
}
}
class Parent extends Grandparent {
public Parent() {
super("Hello.Grandparent.");
System.out.println("Parent Created");
}
}
class Child extends Parent {
public Child() {
System.out.println("Child Created");
}
}
public class Main {
public static void main(String args[]) {
Child c = new Child();
}
}
子类的构造方法在运行之前通常需要调用父类的构造方法,因为这是确保继承体系中的正确初始化和一致性的关键一步。这是基于以下几个原因:
-
初始化继承链:在继承关系中,子类继承了父类的属性和方法。父类可能会有一些关键的初始化操作,这些操作需要在子类的构造方法运行之前执行。通过调用父类的构造方法,确保了整个继承链中的对象都能够正确初始化。
-
父类资源分配:父类的构造方法可能会分配一些资源,如内存、文件句柄、数据库连接等。这些资源需要在子类构造方法之前分配和初始化,以避免资源泄漏或冲突。
-
父类初始化属性:父类可能会在构造方法中初始化一些属性,这些属性可能对子类的构造方法和行为产生影响。子类需要确保在其构造方法运行之前,这些属性已经正确初始化。
虽然子类的构造方法通常需要调用父类的构造方法,但父类的构造方法不能调用子类的构造方法。这是因为子类是基于父类构造的,子类构造方法中可能包含了父类构造方法没有的初始化步骤。如果反过来调用子类构造方法,会导致初始化的顺序混乱,可能会导致不可预测的行为和错误。
总之,调用父类构造方法是确保继承体系正确初始化的关键部分,而反过来调用子类构造方法通常不合适且不安全。在面向对象编程中,遵循调用父类构造方法的惯例是一种良好的实践,以确保继承体系的可靠性和一致性。
构造函数的主要作用是在创建对象时执行必要的初始化操作。构造函数通常是一个特殊的方法或函数,用于为类或对象分配内存空间并设置初始值。它具体的作用包括:
-
分配内存空间:构造函数负责为对象分配内存空间,确保对象具有足够的存储来存储其属性和数据。
-
初始化属性:构造函数用于设置对象的属性或成员变量的初始值。这有助于确保对象在创建后处于一个已知的状态,以避免潜在的错误或不一致性。
-
执行必要的初始化操作:构造函数可以执行与对象相关的任何其他初始化操作,例如打开文件、建立数据库连接、初始化数据结构等。
-
提供灵活性:构造函数通常具有参数,允许在创建对象时传递不同的参数值,从而在不同情况下创建具有不同属性值的对象。
构造函数通常在对象创建时由编程语言的实例化机制自动调用,以确保对象的合理初始化。不同编程语言可能有不同的构造函数语法和约定,但它们都具有相似的目标:初始化新创建的对象。
final声明的方法不能覆写,变量不能更改,类不能被继承
示例中定义了一个类A,它没有任何成员: class A { } 示例直接输出这个类所创建的对象 public static void main(String[] args) { System.out.println(new A()); }
在这个示例中,定义了一个类A,它没有任何成员或属性。然后,在main
方法中,直接创建了一个类A的对象并使用System.out.println
方法将其输出。由于类A没有定义任何属性或方法,输出的结果将会是该对象的默认字符串表示形式。
在Java中,如果类没有显式定义toString
方法,那么将使用从java.lang.Object
类继承的默认toString
方法。默认的toString
方法将返回一个字符串,格式为类的名称,后跟@
符号和对象的哈希码的十六进制表示。例如,输出可能类似于以下内容:
A@15db9742
其中"A"是类的名称,"@15db9742"是对象的哈希码的十六进制表示。
请注意,虽然示例中没有定义任何成员的类A,但每个Java类都继承了一些方法和属性,包括toString
方法,因此即使没有显式定义,也可以使用默认的toString
方法。如果你想要自定义对象的字符串表示形式,你可以重写toString
方法,以便返回你希望的格式。
class Parent {
public Parent() {
System.out.println("Parent Created");
}
public void eat()
{
System.out.println("喝");
}
}
class Child extends Parent {
public Child() {
System.out.println("Child Created");
}
public void eat()
{
System.out.println("睡");
}
}
public class Main {
public static void main(String args[]) {
Child c = new Child();
c.eat();
}
}
(1)覆盖方法的允许访问范围不能小于原方法。
(2)覆盖方法所抛出的异常不能比原方法更多。
(3)声明为final方法不允许覆盖。
例如,Object的getClass()方法不能覆盖。
(4)不能覆盖静态方法。
{
public static void main(String[] args)
{
//声明hello时使用Object类,则hello的编译类型是Object,Object是所有类的父类
//但hello变量的实际类型是String
Object hello = "Hello";
//String是Object类的子类,所以返回true。
System.out.println("字符串是否是Object类的实例:" + (hello instanceof Object));
//返回true。
System.out.println("字符串是否是String类的实例:" + (hello instanceof String));
//返回false。
System.out.println("字符串是否是Math类的实例:" + (hello instanceof Math));
//String实现了Comparable接口,所以返回true。
System.out.println("字符串是否是Comparable接口的实例:" + (hello instanceof Comparable));
String a = "Hello";
//String类既不是Math类,也不是Math类的父类,所以下面代码编译无法通过
//System.out.println("字符串是否是Math类的实例:" + (a instanceof Math));
}
}
-
m=d;
:这个语句不会引起编译错误,因为Dog
是Mammal
的子类,所以将一个Dog
对象分配给Mammal
类型的变量是合法的。这是多态性的一个示例。 -
d=m;
:这个语句将引起编译错误。虽然Dog
是Mammal
的子类,但将一个Mammal
类型的变量分配给Dog
类型的变量需要进行强制类型转换。因为Java编译器不能确定m
引用的对象实际上是Dog
,所以需要显式的类型转换。 -
d=(Dog)m;
:这个语句不会引起编译错误,因为它包含了显式的类型转换,将Mammal
类型的变量m
强制转换为Dog
类型。 -
d=c;
:这个语句将引起编译错误,因为Cat
和Dog
是不同的子类,它们之间没有直接的继承关系。 -
c=(Cat)m;
:这个语句将在运行时引起ClassCastException
异常。即使在编译时没有错误,但因为m
引用的对象是一个Dog
,试图将其强制转换为Cat
是不合法的,因为Dog
和Cat
之间没有继承关系,所以这会导致运行时异常。
有abstract修饰的类称为“抽象类”,它只定义了什么方法应该存在,不能创建对象,必须派生出一个子类,并在子类中实现其未实现的方法之后,才能使用new关键字创建对象。
在方法前加上abstract就形成抽象方法,只有方法声明,没有实现代码
abstract class Person
{
public abstract String getDescription();
}
一个抽象类中可以包含非抽象方法和成员变量。包含抽象方法的类一定是抽象类,但抽象类中的方法不一定是抽象方法
直接定义了一个抽象方法
继承了一个抽象父类,但没有完全实现父类包含的抽象方法
实现了一个接口,但没有完全实现此接口所包容的抽象方法。
定义一个接口,采用关键字interface,实现一个接口,采用关键字implements
接口的成员函数自动成为public的,数据成员自动成为
static和final的。
如果接口不声明为public的,则自动变为package。
一个类可以同时实现多个接口。
本文来自博客园,作者:赵千万,转载请注明原文链接:https://www.cnblogs.com/zhaoqianwan/p/17763298.html
千万千万赵千万