赞
踩
泛化关系,类和类之间的继承关系及接口与接口之间的继承关系
关联关系,类与类之间的连接,一个类可以知道另一个类的属性和方法,在 java 语言中使用实例变量体现。
聚合关系,是关联关系的一种,是较强的关联关系,是整体和部分的关系,如:汽车和轮胎,它与关联关系不同,关联关系的类处在同一个层次上,而聚合关系的类处在不平等的层次上,一个代表整体,一个代表部分,在 java 语言中使用实例变量体现。
合成关系,也是关联关系的一种,是比聚合关系强的关联关系,如:人和四肢,整体对象决定部分对象的生命周期,部分对象每一时刻只与一个对象发生合成关系,在 java 语言中使用实例变量体现。
依赖关系,依赖关系是比关联关系弱的关系,在 java 语言中体现为返回值,参数,局部变量和静态方法调用。
Student is a people,凡是能够满⾜is a的表示“继承关系”。
public class A {
public void method1() {}
}
public class B extends A {
public void method1() {}
}
Cooker is like a menu 或者 driver is like a GPS,凡是能够满足 is like a 关系的表示“实现关系” ,通常为类实现接口(前类后接口)。
public interface I {
public void method1() ;
}
public class A implements I {
public void method1() {
//实现
}
}
I has a pen,凡是能够满⾜has a关系的表示存在“关联关系”,通常以“属性”的形式存在。
public class A {
private B b;
}
public class B {
}
a) Object 类是所有 Java 类的根基类;
b) 如果在类的声明中未使用 extends 关键字指明其基类,则默认基类为 Object 类。
如:
public class User {...}
相当于
public class User extends Object {...}
返回该对象的字符串表示。通常 toString 方法会返回一个“以文本方式表示”此对象的字符串,Object 类的 toString 方法返回一个字符串,该字符串由类名加标记@和此对象哈希码的无符号十六进制表示组成,Object 类 toString 源代码如下:
getClass().getName() + '@' + Integer.toHexString(hashCode())
在进行 String 与其它类型数据的连接操作时,如:System.out.println(student);
,它自动调用该对象的 toString()方法。
package Object; public class ToStringTest01 { public static void main(String[] args) { Person person = new Person(); person.id = 200; person.name = "张三"; //因为它调用了 Object 中的 toString 方法 //输出的格式不友好,无法看懂 System.out.println(person); } } //class Person extends Object { //和以下写法等同 class Person{ int id; String name; }
输出结果(Object是包名,后续会学习到):
覆写Person中的toString方法:
package Object; public class ToStringTest02 { public static void main(String[] args) { Person01 person = new Person01(); person.id = 200; person.name = "张三"; //System.out.println(person.toString()); //输出结果为:{id=200, name=张三} //因为 println 方法没有带 Person 参数的 //而 Person 是 Object,所以他会调用 println(Object x)方法 //这样就是产生 object 对其子类 Person 的指向,而在 Person 中 //覆盖了父类 Object 的 toString 方法,所以运行时会动态绑定 //Person 中的 toString 方法,所以将会按照我们的需求进行输出 System.out.println(person); } } //class Person extends Object { //和以下写法等同 class Person01{ int id; String name; public String toString() { return "{id=" + id + ", name=" + name + "}"; } }
运行结果:
此方法在 Object 类中的实现代码为:
protected void finalize() throw Throwable{}
//只有方法体,里面没有代码。
**注意:**这个方法由JVM垃圾回收器负责调用,不需要手动调用,有需要的话重写即可。
垃圾回收器(Garbage Collection),也叫 GC,垃圾回收器主要有以下特点:
System.gc
和 Runtime.getRuntime().gc()
);finalize
方法;finalize
方法执行时机:
当垃圾收集器将要收集某个垃圾对象时将会调用 finalize,建议不要使用此方法,因为此方法的运行时间不确定,如果执行此方法出现错误,程序不会报告,仍然继续运行。
如下代码:
package Object; public class FinalizeTest01 { public static void main(String[] args) { Person02 person = new Person02(); person.id = 1000; person.name = "张三"; //将 person 设置为 null 表示 person 不再执行堆中的对象 //那么此时堆中的对象就是垃圾对象 //垃圾收集(GC)就会收集此对象 //GC 不会马上收集,收集时间不确定 //但是我们可以告诉 GC,马上来收集垃圾,但也不确定,会马上来 //也许不会来 person = null; //通知垃圾收集器,来收集垃圾 System.gc(); } } class Person02{ int id; String name; //此方法垃圾收集器会调用 public void finalize() throws Throwable { //这里抛出异常,后续会学到 System.out.println("Person.finalize()"); } }
运行结果:
注意如下写法没有意义:
public class FinalizeTest02 { public static void main(String[] args) { method1(); } private static void method1() { Person person = new Person(); person.id = 1000; person.name = "张三"; //这种写法没有多大的意义, //执行完成方法,所有的局部变量的生命周期全部结束 //所以堆区中的对象就变成垃圾了(因为没有引用指向对象了) person = null; } } class Person{ int id; String name; public void finalize() throws Throwable { System.out.println("Person.finalize()"); } }
如下代码:
package Object; public class EqualsTest01 { public static void main(String[] args) { int a = 100; int b = 100; //可以成功比较 //采用等号比较基本类型,它比较的就是具体的值 System.out.println((a == b)?"a==b":"a!=b"); Student s1 = new Student(); s1.id = 1001; s1.name = "张三"; Student s2 = new Student(); s2.id = 1001; s2.name="张三"; //输出为 s1!=s2 //采用等号比较引用类型比较的是引用类型的地址(地址也是值) //这个是不符合我们的比较需求的 //我们比较的应该是对象的具体属性,如:id 相等,或 id 和 name 相等 System.out.println((s1 == s2)?"s1==s2":"s1!=s2"); Student s3 = s1; //输出为 s1==s3 //因为 s1 和 s3 指向的是一个对象,所以地址一样 //所以采用等号比较引用类型比较的是地址 System.out.println((s1 == s3)?"s1==s3":"s1!=s3"); String str1 = "abc"; String str2 = "abc"; //输出 s1==s2 System.out.println((str1==str2)?"str1==str2":"str1=str2"); } } class Student{ int id; String name; }
运行结果:
package Object; public class EqualsTest02 { public static void main(String[] args) { String s1 = "abc"; String s2 = "abc"; //输出 s1==s2 System.out.println((s1==s2)?"s1==s2":"s1=s2"); //与上创建String字符串的方式不一致,这两种方式的区别后续学习String时会了解到,输出s3!=s4 String s3 = new String("abc"); String s4 = new String("abc"); System.out.println((s3==s4)?"s3==s4":"s3!=s4"); //输出 s3 等于 s4,所以确定 String 的 equals 比较的是具体的内容 System.out.println(s3.equals(s4)? "s3 等于 s4": "s3 不等于 s4"); Animal a1 = new Animal(); a1.id = 1001; a1.name = "张三"; Animal a2 = new Animal(); a2.id = 1001; a2.name="张三"; //输出:a1 不等于 a2 //因为它默认调用的是 Object 的 equals 方法 //而 Object 的 equals 方法默认比较的就是地址,Object 的 equals 方法代码如下: // public boolean equals(Object obj) { // return (this == obj); // } //如果不准备调用父类的 equals 方法,那么必须覆盖父类的 equals 方法行为 System.out.println(a1.equals(a2)? "a1 等于 a2": "a1 不等于 a2"); } } class Animal{ int id; String name; }
运行结果:
进一步完善,覆写equals方法:
package Object; public class EqualsTest03 { public static void main(String[] args) { Animal01 a1 = new Animal01(); a1.id = 11; a1.name = "元宝"; Animal01 a2 = new Animal01(); a2.id = 11; a2.name = "元宝"; System.out.println((a1.equals(a2))?"a1与a2相等":"a1与a2不相等"); } } class Animal01{ int id; String name; // 覆盖父类方法,加入自己的比较规则 @Override public boolean equals(Object obj) { if(this == obj){ return true; } // 确定比较类型为Animal01,同一类型才具有可比性 if(obj instanceof Animal01){ // 强制向下转型 Animal01 animal01 = (Animal01)obj; // 如果id相等就认为相等 if(this.id == animal01.id){ return true; } } return false; } }
运行结果:
判断是否相等的总结:
equals()
方法,需要覆写定义规则来进行具体的判断。包(package)其实就是目录,特别是项目比较大,java 文件特别多的情况下,我们应该分目录管理,在 java
中称为分包管理。
包的命名规范:
com.sunny.exam
package 必须放到 所有语句的第一行,注释除外
package packagetest;
public class PackageTest01 {
public static void main(String[] args) {
}
}
此时,若使用命令行编译运行PackageTest01,应带上包名,即:java packagetest PackageTest01
。
如何使用包下的class 文件=>采用import
引入所需要使用的类
如下代码:
package user; public class User { int id; String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
package packagetest;
import user.User;
//可以采用 * 通配符引入包下的所有类
//此种方式不明确,但简单
//其中,*只代表类名,不能代表包,所以包的路径必须到最后一层包名再.*
//import user.*;
public class PackageTest02 {
public static void main(String[] args) {
User user = new User();
user.setId(10000);
user.setName("张三");
}
}
如果都在同一个包下就不需要 import 引入了,在实际开发过程中不应该这样做,必须建立包!
由于String、System等类在java.lang包中,这个包中的类一律不用导。
java 访问级别修饰符主要包括:private
、protected
和 public
,可以限定其他类对该类的属性和方法的使用权限。
修饰符 | 类的内部 | 同一个包里 | 子类 | 任何地方 |
---|---|---|---|---|
private | √ | × | × | × |
default | √ | √ | × | × |
protected | √ | √ | √ (不同包中的子类也可以) | × |
public | √ | √ | √ | √ |
注意:以上对类的修饰只有:public 和 default,内部类除外。
private 声明的变量或方法,只能在同一个类中使用。
package accesstest;
public class PrivateTest {
public static void main(String[] args) {
A a = new A();
//无法访问
System.out.println(a.id);
}
}
class A{
private int id;
}
编译报错:
为了访问private属性或方法,需要在该类中定义public方法,比如setter和getter方法访问private类型的属性。
采用 protected 声明的变量或方法只有子类或同一个包下的类可以调用。
package accesstest.protectedtest; public class ProtectedTest01 { public static void main(String[] args) { A a = new A(); //可以正确调用,在同一个包下 System.out.println(a.id); a.method1(); A b = new B(); b.method1(); B b1 = new B(); b1.method3(); } } class A{ //采用 protected 声明的变量 protected int id = 100; public void method1() { System.out.println(id); } //采用 protected 声明的方法 protected void method2() { System.out.println("A.method2()"); } } class B extends A{ public void method1() { //子类可以正确调用 System.out.println(id); } public void method3() { //子类可以正确调用 method2(); } }
运行结果:
package accesstest.protectedtest2; import accesstest.protectedtest1.C1; public class ProtectedTest02 { public static void main(String[] args) { C1 c1 = new C1(); //无法访问,不能在其他类中访问 protected 声明的方法或变量 System.out.println(c1.id); C1 c2 = new C2(); ((C2) c2).method2(); } } class C2 extends C1{ public void method2() { //可以调用,主要原因 C2 是 C1 的子类 //所以可以访问 protected 声明的变量 System.out.println(id); method1(); } } class C3 { //不能在其他类中访问 protected 声明的方法或变量 new C1().method1(); }
编译报错:
注释上述编译报错行后运行结果:
如果 class 不采用 public 修饰,那么此时的 class,只能被该包下的类访问,其他包下无法访问。
package accesstest.test;
class D {
public void method(){
System.out.println("D.method()");
}
}
package accesstest.defaulttest;
//不能访问,只有在一个类中或在同一个包下可以访问
import accesstest.test.D;
public class DefaultTest {
public static void main(String[] args) {
D d = new D();
}
}
package accesstest.defaulttest;
//在子类中也不能访问
import accesstest.test.D;
public class E extends D {
}
编译报错:
package accesstest.test;
public class defaultTest1 {
public static void main(String[] args) {
//可以在同一个包中访问
D d = new D();
d.method();
}
}
运行结果:
在一个类的内部定义的类,称为内部类,主要分为:
三种内部类均可以使用public、protected、default(不写)、private修饰。
如下代码:
package innerclasstest; public class InnerClassTest01 { private int a; private int b; public InnerClassTest01(int a, int b) { this.a = a; this.b = b; } private class Inner1{ int i1 = 0; int i2 = 1; int i3 = a; int i4 = b; //不能有static成员 static int i5 = 20; } }
编译报错:
测试:
package innerclasstest; public class InnerClassTest01 { private int a; private int b; public InnerClassTest01(int a, int b) { this.a = a; this.b = b; } private class Inner1{ int i1 = 1; int i2 = 2; //可以直接使用外部类的实例变量 int i3 = a; int i4 = b; //不能有static成员 // static int i5 = 20; } public static void main(String[] args) { //通过外部类创建内部类 InnerClassTest01.Inner1 inner1 = new InnerClassTest01(10,20).new Inner1(); System.out.println(inner1.i1); System.out.println(inner1.i2); System.out.println(inner1.i3); System.out.println(inner1.i4); } }
运行结果:
如下代码:
package innerclasstest; public class InnerClassTest02 { static int a = 100; int b = 300; static class Inner2{ //在静态内部类中可以定义实例变量 int i1 = 10; int i2 = 20; //在静态内部类中可以定义静态变量 static int i3 = 100; //可以直接使用外部类的静态变量 static int i4 = a; //不能直接引用外部类的实例变量 int i5 = b; //采用外部类的引用可以取得外部类的实例变量的值 int i6 = new InnerClassTest02().b; } }
编译报错:
测试:
package innerclasstest; public class InnerClassTest02 { static int a = 100; int b = 300; static class Inner2{ //在静态内部类中可以定义实例变量 int i1 = 10; int i2 = 20; //在静态内部类中可以定义静态变量 static int i3 = 200; //可以直接使用外部类的静态变量 static int i4 = a; //不能直接引用外部类的实例变量 // int i5 = b; //采用外部类的引用可以取得外部类的实例变量的值 int i6 = new InnerClassTest02().b; public static void main(String[] args) { //可以直接创建静态内部类对象 InnerClassTest02.Inner2 inner2 = new InnerClassTest02.Inner2(); System.out.println(inner2.i1); System.out.println(inner2.i2); System.out.println(inner2.i3); System.out.println(inner2.i4); System.out.println(inner2.i6); } } }
运行结果:
如下代码:
package innerclasstest; public class InnerClassTest03 { private int a = 200; public void method1(int temp){ //在方法中定义局部内部类 class Inner3{ int i1 = 100; //可以访问外部内的成员变量 int i2 = a; int i3 = temp; //不能定义静态变量 static int i4 = 4; } //使用局部内部类 Inner3 inner3 = new Inner3(); System.out.println(inner3.i1); System.out.println(inner3.i2); System.out.println(inner3.i3); } }
编译报错:
测试:
package innerclasstest; public class InnerClassTest03 { private int a = 200; public void method1(int temp){ //在方法中定义局部内部类 class Inner3{ int i1 = 100; //可以访问外部内的成员变量 int i2 = a; int i3 = temp; //不能定义静态变量 // static int i4 = 4; } //创建局部内部类对象 Inner3 inner3 = new Inner3(); System.out.println(inner3.i1); System.out.println(inner3.i2); System.out.println(inner3.i3); } public static void main(String[] args) { InnerClassTest03 innerClassTest03 = new InnerClassTest03(); innerClassTest03.method1(300); } }
运行结果:
匿名内部类是一种特殊的内部类,该类没有名字。
缺点:太复杂、乱,可读性差;不可重复使用,就是看着高端,自己不写,能看懂别人写的就行。
package innerclasstest; public class InnerClassTest04 { public static void main(String[] args) { MyInterface myInterface = new MyInterfaceImpl(); myInterface.add(); } } interface MyInterface{ void add(); } class MyInterfaceImpl implements MyInterface{ @Override public void add() { System.out.println("---------add---------"); } }
运行结果:
package innerclasstest; public class InnerClassTest05 { public static void main(String[] args) { InnerClassTest05 innerClassTest05 = new InnerClassTest05(); innerClassTest05.method1(new MyInterface01(){ //对接口的实现,覆写其中的add()方法 //这个表面上看上去好像是在直接new 接口MyInterface,但是实际上并不是,后面的{}代表类对接口的实现 @Override public void add() { System.out.println("-------add-------"); } }); } private void method1(MyInterface01 myInterface01){ myInterface01.add(); } } interface MyInterface01{ void add(); }
运行结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。