父类也称作超类、基类、派生类等。
Java中只有单继承,没有像C++那样的多继承。多继承会引起混乱,使得继承链过于复杂,系统难于维护。
Java中类没有多继承,接口有多继承。
子类继承父类,可以得到父类的全部属性和方法 (除了父类的构造方法),但不见得可以直接访问(比如,父类私有的属性和方法)。
如果定义一个类时,没有调用extends,则它的父类是:java.lang.Object。
“==”: 方法名、形参列表相同。
“≤”:返回值类型和声明异常类型,子类小于等于父类。
“≥”: 访问权限,子类大于等于父类。
package cn.amaris.oo2;
public class TestExtends {
public static void main(String[] args) {
Student s1 = new Student();
s1.study();
s1.rest();
Student s2 = new Student("Amaris",172,"CS");
System.out.println(s2 instanceof Student);
}
}
class Person{
String name;
int height;
public void rest() {
System.out.println("resting...");
}
}
class Student extends Person{
String major;
public Student(String name,int height,String major) {
this.name = name;
this.height = height;
this.major = major;
}
public Student() {
//空构造器,重载
}
public void rest() {
// 方法的重写
System.out.println("Listening...");
}
public void study() {
System.out.println("studying...");
}
}
package cn.amaris.oo2;
public class TestToString {
public static void main(String[] args) {
TestToString t = new TestToString();
System.out.println(t.toString());
System.out.println(t);
}
public String toString() {
//重写
return "test toString";
}
}
package cn.amaris.oo2;
public class TestEquals {
public static void main(String[] args) {
Object obj;
String str;
User u1 = new User(24,"A","123456");
User u2 = new User(24,"A","123456");
System.out.println(u1 == u2);
System.out.println(u1.equals(u2));
}
}
class User {
int id;
String name;
String pwd;
public User(int id, String name, String pwd) {
super();
this.id = id;
this.name = name;
this.pwd = pwd;
}
}
package cn.amaris.oo2;
public class TestEquals {
public static void main(String[] args) {
Object obj;
String str;
User u1 = new User(24,"A","123456");
User u2 = new User(24,"A","123456");
System.out.println(u1 == u2);
System.out.println(u1.equals(u2));
}
}
class User {
int id;
String name;
String pwd;
public User(int id, String name, String pwd) {
super();
this.id = id;
this.name = name;
this.pwd = pwd;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (id != other.id)
return false;
return true;
}
}
public class TestSuper01 {
public static void main(String[] args) {
new ChildClass().f();
}
}
class FatherClass {
public int value;
public void f(){
value = 100;
System.out.println ("FatherClass.value="+value);
}
}
class ChildClass extends FatherClass {
public int value;
public void f() {
super.f(); //调用父类对象的普通方法
value = 200;
System.out.println("ChildClass.value="+value);
System.out.println(value);
System.out.println(super.value); //调用父类对象的成员变量
}
}
查找当前类中有没有属性h
依次上溯每个父类,查看每个父类中是否有h,直到Object
如果没找到,则出现编译错误。
上面步骤,只要找到h变量,则这个过程终止。
构造方法调用顺序
构造方法第一句总是:super(…)来调用父类对应的构造方法。所以,流程就是:先向上追溯到Object,然后再依次向下执行类的初始化块和构造方法,直到当前子类为止。
注:静态初始化块调用顺序,与构造方法调用顺序一样,不再重复。
public class TestSuper02 {
public static void main(String[] args) {
System.out.println("开始创建一个ChildClass对象......");
new ChildClass();
}
}
class FatherClass {
public FatherClass() {
System.out.println("创建FatherClass");
}
}
class ChildClass extends FatherClass {
public ChildClass() {
System.out.println("创建ChildClass");
}
}
private 表示私有,只有自己类能访问
default 表示没有修饰符修饰,只有同一个包的类能访问
protected 表示可以被同一个包的类以及其他包中的子类访问
public 表示可以被该项目的所有包中的所有类访问
package cn.amaris.oo2;
public class Human{
private int age;
public String name;
protected int height;
void sayAge() {
System.out.println(age);
}
}
class Boy extends Human{
void sayHello() {
System.out.println(height); // age,private
}
}
package cn.amaris.oo3;
import cn.amaris.oo2.*;
public class TestEncapsulation2 {
public static void main(String[] args) {
Human h2 = new Human();
h2.name = "Jorge";
Girl b1 = new Girl();
}
}
class Girl extends Human{
void sayHello() {
System.out.println(height); // age,private
}
}
一般使用private访问权限。
提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,以提供对属性的赋值与读取操作(注意:boolean变量的get方法是is开头!)。(右键->source->set/get…自动生成)
一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法用public修饰。(通常 public)
package cn.amaris.oo3;
public class Person {
private int id;
private String name;
private int age;
private boolean man;
public void setName(String name) {
this.name = name;
}
public String getName(){
return this.name;
}
public void setAge(int age) {
if(age>=0&&age<=130) {
this.age = age;
}else {
System.out.println("Error age!");
}
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public boolean isMan() {
return man;
}
public void setMan(boolean man) {
this.man = man;
}
public int getAge() {
return this.age;
}
}
package cn.amaris.oo2;
import cn.amaris.oo3.*;
public class Human{
public static void main(String[] args) {
Person p1 = new Person();
p1.setName("Amaris");
p1.setAge(20);
System.out.println(p1.getAge());
System.out.println(p1.getName());
}
}
有抽象方法的类只能定义成抽象类
抽象类不能实例化,即不能用new来实例化抽象类。
抽象类可以包含属性、方法、构造方法。但是构造方法不能用来new实例,只能用来被子类调用。
抽象类只能用来被继承。
抽象方法必须被子类实现。
package cn.amaris.proj0501;
abstract public class TestAbstract {
public static void main(String[] args) {
Dog d = new Dog();
d.shout();
}
}
abstract class Animal {
abstract public void shout();
public void run() {
System.out.println("Runing...");
}
}
class Dog extends Animal{
public void shout() {
System.out.println("wang.wang.wang...");
}
}
从接口的实现者角度看,接口定义了可以向外部提供的服务。
从接口的调用者角度看,接口定义了实现者能提供那些服务。
**接口是两个模块之间通信的标准,通信的规范。**如果能把你要设计的模块之间的接口定义好,就相当于完成了系统的设计大纲,剩下的就是添砖加瓦的具体实现了。大家在工作以后,做系统时往往就是使用“面向接口”的思想来设计系统。
**接口和实现类不是父子关系,是实现规则的关系。**比如:我定义一个接口Runnable,Car实现它就能在地上跑,Train实现它也能在地上跑,飞机实现它也能在地上跑。就是说,如果它是交通工具,就一定能跑,但是一定要实现Runnable接口。
** 接口的本质探讨**
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是…则必须能…”的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你是好人,则必须能干掉坏人;如果你是坏人,则必须欺负好人。
接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。
面向对象的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如C++、Java、C#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。
区别
普通类:具体实现
抽象类:具体实现,规范(抽象方法)
接口:规范!
访问修饰符:只能是public或默认。
接口名:和类名采用相同命名机制。
extends:接口可以多继承。(普通类只有单继承)
接口完全支持多继承。和类的继承类似,子接口扩展某个父接口,将会获得父接口中所定义的一切。
常量:接口中的属性只能是常量,总是:public static final 修饰。不写也是。
方法:接口中的方法只能是:public abstract。 省略的话,也是public abstract。
package cn.amaris.proj0501;
public interface MyInterface {
int MAX_AGE = 130;
void test01();
public static void main(String[] args) {
SubInterface s = new SubInterface();
s.test01();
}
}
class SubInterface implements MyInterface{
public void test01() {
System.out.println("test SubInterface!");
}
}
package cn.amaris.proj0501;
public class TestMyinterface {
public static void main(String[] args) {
Angel a = new Angel();
a.fly();
a.helpOther();
}
}
interface Volant{
int FLY_HEIGHT = 1000;
void fly();
}
interface Honest{
void helpOther();
}
class Angel implements Volant,Honest{
@Override
public void helpOther() {
System.out.println("Helping...");
}
@Override
public void fly() {
System.out.println("Flying...");
}
}
面向接口编程是面向对象编程的一部分。
软件设计中最难处理的就是需求的复杂变化,需求的变化更多的体现在具体实现上。
通过面向接口编程,而不是面向实现类编程,可以大大降低程序模块间的耦合性,提高整个系统的可扩展性和和可维护性。
面向接口编程的概念比接口本身的概念要大得多。设计阶段相对比较困难,在你没有写实现时就要想好接口,接口一变就乱套了,所以设计要比实现难!
内部类提供了更好的封装。只能让外部类直接访问,不允许同一个包中的其他类直接访问。
内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员。 但外部类不能访问内部类的内部属性。
接口只是解决了多重继承的部分问题,而内部类使得多重继承的解决方案变得更加完整。
非静态内部类必须寄存在一个外部类对象里。因此,如果有一个非静态内部类对象那么一定存在对应的外部类对象。非静态内部类对象单独属于外部类的某个对象。
非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员。
非静态内部类不能有静态方法、静态属性和静态初始化块。
外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例。
成员变量访问要点:
a. 内部类里方法的局部变量:变量名。
b. 内部类属性:this.变量名。
c. 外部类属性:外部类名.this.变量名。
package cn.amaris.proj0501;
public class TestInnerClass {
public static void main(String[] args) {
//创建内部类对象
Outer.Inner inner = new Outer().new Inner();
inner.show();
}
}
class Outer{
private int age = 10;
public void testOuter() {
System.out.println("test outer...");
}
class Inner{
int age = 20;
public void show() {
int age = 30;
System.out.println("外部类的成员变量 age: "+Outer.this.age);
System.out.println("内部类的成员变量 age: "+this.age);
System.out.println("局部变量 age: "+age);
}
}
}
使用要点:
a. 当一个静态内部类对象存在,并不一定存在对应的外部类对象。
因此,静态内部类的实例方法不能直接访问外部类的实例方法。
b. 静态内部类看做外部类的一个静态成员。 因此,外部类的方法
中可以通过:“静态内部类.名字”的方式访问静态内部类的静态成
员,通过 new 静态内部类()访问静态内部类的实例。
package cn.amaris.proj0501;
public class TestStaticInner {
public static void main(String[] args) {
Outer2.Inner2 inner = new Outer2.Inner2();
inner.test2();
}
}
class Outer2{
static class Inner2{
public void test2() {
System.out.println("test static inner2...");
}
}
}
package cn.amaris.proj0501;
public class TestAnonymousInnerClass {
public static void test01(C1 c) {
c.testc1();
}
public static void main(String[] args) {
TestAnonymousInnerClass.test01(new C1() {
@Override
public void testc1() {
System.out.println("test anonymousInnerClass...");
}
});
}
}
interface C1{
void testc1();
}
String类和常量池
全局字符串常量池(String Pool)
全局字符串常量池中存放的内容是在类加载完成后存到String Pool中的,在每个VM中只有一份,存放的是字符串常量的引用值(在堆中生成字符串对象实例)。
字符串比较用equals
class文件常量池(Class Constant Pool)
class常量池是在编译的时候每个class都有的,在编译阶段,存放的是常量(文本字符串、final常量等)和符号引用。
运行时常量池(Runtime Constant Pool)
运行时常量池是在类加载完成之后,将每个class常量池中的符号引用值转存到运行时常量池中,也就是说,每个class都有一个运行时常量池,类在解析之后,将符号引用替换成直接引用,与全局常量池中的引用值保持一致。
Java SE Development Kit 8 Documentation
提取码:h100
面向过程与面向对象都是解决问题的思维方式,都是代码组织的方式。
解决简单问题可以使用面向过程。
解决复杂问题:宏观上使用面向对象把握,微观处理上仍然是面向过程。
对象和类的关系是特殊到一般,具体到抽象的关系。
栈内存
每个线程私有,不能实现线程间的共享!
局部变量放置于栈中。
栈是由系统自动分配,速度快!栈是一个连续的内存空间!
放置new出来的对象!
堆是一个不连续的内存空间,分配灵活,速度慢!
被所有线程共享!
用来存放程序中永远是不变或唯一的内容(类代码信息、静态变量、字符串常量)。
属性用于定义该类或该类对象包含的数据或者说静态属性。属性作用范围是整个类体。Java使用默认的值对其初始化。
方法则用于定义该类或该类实例的行为特征和功能实现。方法是类和对象行为特征的抽象。
构造器又叫做构造方法(constructor),用于构造该类的实例。Java通过new关键字来调用构造方法,从而返回该类的实例,是一种特殊的方法。
垃圾回收机制
程序员无权调用垃圾回收器。
程序员可以通过System.gc()通知垃圾回收器(Garbage Collection,简称GC)运行,但是Java规范并不能保证立刻运行。
finalize方法,是Java提供给程序员用来释放对象或资源的方法,但是尽量少用。
方法的重载是指一个类中可以定义有相同的名字,但参数不同的多个方法。 调用时,会根据不同的参数表选择对应的方法。
this关键字的作用
让类中的一个方法,访问该类的另一个方法或属性。
使用this关键字调用重载构造方法,可以避免相同的初始化代码,只能在构造方法中用,并且必须位于构造方法的第一句。
在类中,用static声明的成员变量为静态成员变量,也称为类变量。
用static声明的方法为静态方法。
可以通过对象引用或类名(不需要实例化)访问静态成员。
可以解决类之间的重名问题。
便于管理类:合适的类位于合适的包!
impport的作用
通过import可以导入其他包下面的类,从而可以在本类中直接通过类名来调用。
super关键字的作用
super是直接父类对象的引用。可以通过super来访问父类中被子类覆盖的方法或属性。
面向对象的三大特征:继承、封装、多态。
Object类是所有Java类的根基类。
访问权限控制符:范围由小到大分别是private、default、protected、public。
引用变量名 instanceof 类名 来判断该引用类型变量所“指向”的对象是否属于该类或该类的子类。
final关键字可以修饰变量、修饰方法、修饰类。
抽象类是一种模版模式。抽象类为所有子类提供了一个通用模版,子类可以在这个模版基础上进行扩展,使用abstract修饰。
使用abstract修饰的方法为抽象方法必须被子类实现,除非子类也是抽象类。
使用interface声明接口
从接口的实现者角度看,接口定义了可以向外部提供的服务。
从接口的调用者角度看,接口定义了实现者能提供哪些服务。
内部类分为成员内部类、匿名内部类和局部内部类。
String位于java.lang包中,Java程序默认导入java.lang包。
字符串的比较"=="与equals()方法的区别。