自学JavaDay11
Object类
/*
java.lang.Object类
1.Object类是所有Java类的根父类
2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
3.Object类中的功能(属性、方法)就具有通用性
属性:无
方法:equals()/toString()/getClass()/hashCode()/clone()/finalize()/
wait()/notify()/notifyAll()
4.Object类中只声明了一个空参构造器
面试题:
final、finally、finalize的区别?
*/
public class ObjectTest {
public static void main(String[] args) {
Order order = new Order();
System.out.println(order.getClass().getSuperclass());
}
}
class Order{
}
equals()方法
基本使用
package com.oop.demo08;
/*
面试题:==和equals()的区别
一、回顾 == 的使用:
==:运算符
1. 可以使用在基本数据类型变量和引用数据类型变量中
2. 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同)
如果比较的是引用数据类型变量:比较两个对象的地址值是否相同,即是否指向同一个对象实体。
二、equals()方法的使用:
1. 是一个方法,而非运算符
2. 只适用于引用数据类型
3. Objetc类中equals()的定义:
public boolean equals(Object obj) {
return (this == obj);
}
说明:Object类中定义的equals()和==作用相同
4. String、Date、File、包装类等都重写了Object类中的equals()方法。
重写之后比较的是两个对象的实体内容。
5. 通常情况下,自定义类中如需使用equals()方法比较两个对象试题内容,需重写equals()方法。
原则:比较两个对象的实体内容
补充:使用 == 符号时,两边对象类型应保持一致
*/
import java.util.Date;
public class EqualsTest {
public static void main(String[] args) {
int i = 10;
int j = 10;
double d = 10.0;
System.out.println(i == j);//true
System.out.println(i == d);//true
boolean b = true;
// System.out.println(i == b);
char c = 10;
System.out.println(i == c);//true
char c1 = 'A';
char c2 = 65;
System.out.println(c1 == c2);//true
Customer cust1 = new Customer("Tom",21);
Customer cust2 = new Customer("Tom",21);
System.out.println(cust1 == cust2);//false
String st1 = new String("tuhong");
String st2 = new String("tuhong");
System.out.println(st1 == st2);//false
System.out.println("=============================");
System.out.println(cust1.equals(cust2));//false--重写equals()之后为true
System.out.println(st1.equals(st2));//true
Date date1 = new Date(56565778888L);
Date date2 = new Date(56565778888L);
System.out.println(date1.equals(date2));//true
}
}
重写equals()方法--两个例子
package com.oop.demo08.exer;
public class MyDateTest {
public static void main(String[] args) {
MyDate m1 = new MyDate(14,3,1976);
MyDate m2 = new MyDate(14,3,1976);
if(m1 == m2){
System.out.println("m1==m2");
}else{
System.out.println("m1!=m2");
}
if(m1.equals(m2)){
System.out.println("m1 equals to m2");
}else{
System.out.println("m1 do not equals to m2");
}
}
}
class MyDate{
private int day;
private int month;
private int year;
public MyDate(int day, int month, int year) {
this.day = day;
this.month = month;
this.year = year;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public boolean equals(Object obj){
if(this == obj) return true;
if(obj == null || getClass() != obj.getClass()) return false;
MyDate myDate = (MyDate) obj;
return this.day == myDate.day &&
this.month == myDate.month &&
this.year == myDate.year;
}
}
package com.oop.demo08.exer;
public class OrderTest {
public static void main(String[] args) {
Order o1 = new Order(1001,"RTX3090");
Order o2 = new Order(1001,"RTX3080");
System.out.println(o1.equals(o2));
Order o3 = new Order(1001,"RTX3080");
System.out.println(o2.equals(o3));
}
}
class Order {
private int orderId;
private String orderName;
public Order() {
}
public Order(int orderId, String orderName) {
this.orderId = orderId;
this.orderName = orderName;
}
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public boolean equals(Object obj){
if(this == obj) return true;
if(obj == null || getClass() != obj.getClass()) return false;
Order order = (Order) obj;
return this.orderId == order.orderId && this.orderName.equals(order.orderName);
}
}
toString()方法
package com.oop.demo08;
/*
Object类中,toString()的使用
1. 我们输出一个对象时,实际上是在调用对象的toString()方法
2. Object类中,toString()的定义
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
3. String、Date、File、包装类等都重写了Object类中的toString()方法,
在调用toString()方法时,返回实体内容。
4. 自定义类可重写toString()方法,输出对象实体内容。
*/
import java.util.Date;
public class ToStringTest {
public static void main(String[] args) {
Customer cust = new Customer("Tom",21);
System.out.println(cust.toString());//com.oop.demo08.Customer@1b6d3586-->Customer{name='Tom', age=21}
System.out.println(cust);//com.oop.demo08.Customer@1b6d3586
String str = new String("AA");
System.out.println(str);//AA
Date date = new Date(438458559606L);
System.out.println(date);//Thu Nov 24 02:02:39 CST 1983
}
}
单元测试与包装类
package com.th1024.java1;
import org.junit.Test;
public class WrapperTest {
/*
关于包装类使用面试题
*/
@Test
public void test6(){
Object o1 = true ? new Integer(1) : new Double(2.0);//冒号两边类型自动提升至统一
System.out.println(o1);//1.0
}
@Test
public void test7(){
Object o2;
if(true) o2 = new Integer(1);
else o2 = new Double(2.0);
System.out.println(o2);
}
@Test
public void test8(){
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);//false
Integer m = 1;
Integer n = 1;
System.out.println(m == n);//true
//Integer内部定义了Integer cache[] -- 范围:-128-127
//如果使用自动装箱的方式给Integer赋值时,值在范围内,直接使用数组中的元素
//目的:提高效率
Integer x = 128;
Integer y = 128;
System.out.println(x == y);//false
}
//String类型--->基本数据类型,包装类:调用包装类的parseXxx()
@Test
public void test5(){
String str1 = "123";
//错误情况
// int num1 = (int) str1;
// Integer in1 = (Integer) str1;
int num2 = Integer.parseInt(str1);
System.out.println(num2);
String str2 = "true";
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1);
}
//基本数据类型,包装类--->String类型:调用String重载的valueOf(Xxx xxx)
@Test
public void test4(){
int num1 = 10;
//方式1:连接运算
String str1 = num1 + "";
//方式2:调用String重载的valueOf(Xxx xxx)
float f1 = 12.3f;
String str2 = String.valueOf(f1);
Double d1 = 12.3;
String str3 = String.valueOf(d1);
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
}
/*
JDK5.0新特性:自动装箱与自动拆箱
*/
@Test
public void test3(){
//自动装箱:基本数据类型--->包装类
int num1 = 10;
method(num1);
Integer in1 = num1;
boolean b1 = true;
Boolean b2 = b1;
//自动拆箱:包装类-->基本数据类型
int num3 = in1;
System.out.println(num3 + 1);
}
public void method(Object obj){
System.out.println(obj);
}
//包装类-->基本数据类型:调用包装类的xxxValue()
@Test
public void test2(){
Integer in1 = new Integer(12);
int i1 =in1.intValue();
System.out.println(i1 + 1);
Float f1 = new Float(12.3f);
float f2 = f1.floatValue();
System.out.println(f2 + 1);
}
//基本数据类型--->包装类:调用包装类的构造器
@Test
public void test1(){
int num1 = 10;
Integer in1 = new Integer(num1);
System.out.println(in1.toString());
Integer in2 = new Integer("123");
System.out.println(in2.toString());
//报异常
// Integer in3 = new Integer("123abc");
Float f1 = new Float(12.3f);
Float f2 = new Float("12.3f");
System.out.println(f1);
System.out.println(f2);
Boolean b1 = new Boolean(true);
Boolean b2 = new Boolean("true");
Boolean b3 = new Boolean("true123");//false
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
Order order = new Order();
System.out.println(order.isMale);//false
System.out.println(order.isFemale);//null
}
}
class Order{
boolean isMale;
Boolean isFemale;
}
static关键字
package com.oop.demo08;
/*
static关键字的使用
1. static:静态的
2. 可以修饰:属性、方法、代码块、内部类
3. 使用static修饰属性:静态变量/类变量
3.1 属性,按是否使用static修饰,分为:静态变量 vs 非静态变量(实例变量)
实例变量:创建了多个对象,每个对象都独立地拥有一套类中的非静态变量
静态变量:创建了多个对象,每个对象都共享同一个静态变量
3.2 static修饰属性的其他说明:
① 静态变量随着类的加载而加载,可通过"类.静态变量”的方式进行调用
② 静态变量加载早于对象的创建
③ 由于类只会加载一次,静态变量在内存中只有一份,存放于方法区的静态域中
④ 类变量 实例变量
类 yes no(编译不通过)
对象 yes yes
3.3 静态属性举例:System.out、Math.PI
4. 使用static修饰方法:静态方法
① 随着类的加载而加载,可通过“类.静态方法”的方式进行调用
② 静态方法 非静态方法
类 yes no(编译不通过)
对象 yes yes
③ 静态方法中,只能调用静态方法或属性
非静态方法中,既可以调用静态方法或属性,也可以调用非静态方法或属性
5. static注意点
5.1 在静态方法中,不能使用this和super关键字
5.2 关于静态属性和静态方法,从生命周期的角度去理解
6. 开发中如何确定一个属性是否要声明为static?
>属性可以被多个对象共享,不会随着对象的不同而不同
>类中的常量也常声明为static
开发中如何确定一个方法是否要声明为static?
>操作静态属性的方法,通常声明为static
>工具类中的方法,习惯上声明为static,比如:Math、Arrays、Collections
*/
public class StaticTest {
public static void main(String[] args) {
Chinese.nation = "中国";
Chinese c1 = new Chinese();
c1.name = "姚明";
c1.age = 40;
Chinese c2 = new Chinese();
c2.name = "马龙";
c2.age = 30;
c1.nation = "CHN";
System.out.println(c2.nation);
c1.eat();
Chinese.show();
}
}
class Chinese{
String name;
int age;
static String nation;
public void eat(){
System.out.println("吃饭");
}
public static void show(){
System.out.println("我是一个中国人");
}
}
单例模式
package com.oop.demo08.Singleton;
/*
单例设计模式
1. 所谓类的单例设计模式,就是采取一定方法保证在整个软件系统中对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
2. 如何实现?
饿汉式 vs 懒汉式
3. 区分饿汉式和懒汉式
饿汉式:
坏处:对象加载时间长
好处:饿汉式是线程安全的
懒汉式:
好处:延迟对象的创建
坏处:目前的写法是线程不安全的
*/
public class SingletonTest1 {
public static void main(String[] args) {
Bank bank1 = Bank.getInstance();
Bank bank2 = Bank.getInstance();
System.out.println(bank1 == bank2);//true,为同一个对象
}
}
//饿汉式
class Bank{
//1.私有化类的构造器
private Bank(){
}
//2.内部创建类的对象
//4.要求此对象也必须声明为静态的
private static Bank instance = new Bank();
//3.提供公共的static方法,返回类的对象
public static Bank getInstance(){
return instance;
}
}
package com.oop.demo08.Singleton;
/*
单例模式的懒汉式实现
*/
public class SingletonTest2 {
public static void main(String[] args) {
Order o1 = Order.getInstance();
Order o2 = Order.getInstance();
System.out.println(o1 == o2);//true
}
}
class Order{
//1.私有化类的构造器
private Order(){
}
//2.先声明当前类的对象,没有初始化
//4.此对象也必须声明为static
private static Order instance = null;
//3.声明public、static的返回当前对象的方法
public static Order getInstance(){
if(instance == null){
instance = new Order();
}
return instance;
}
}
应用场景
网站的计数器 ,一般也是单例模式实现,否则难以同步。
应用程序的日志应用 ,一般都使用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有个实例去操作,否则内容不好追加。
数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源 。
项目中,读取配置文件的类,一般也只有一个对象。没必要每次使用配置文件数据 ,都生成一个对象去读取 。
Application 也是单例的典型应用
Windows的Task Manager (任务管理器)就是很典型的单例模式
Windows的Recycle Bin (回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例 。
代码块
package com.oop.demo08;
/*
类的成员之四:代码块(或初始化块)
1. 代码块的作用:通常用来初始化类、对象
2. 代码块只能使用static修饰或者无修饰符
3. 分类:静态代码块 vs 非静态代码块
4. 静态代码块
>内部可以有输出语句
>随着类的加载而执行,且只执行一次
>作用:初始化类的信息
>静态代码块内只能调用静态的属性和静态的方法,不能调用非静态结构
非静态代码块
>内部可以有输出语句
>随着对象的创建而执行,每创建一个对象就执行一次非静态代码块
>作用:可以在创建对象时,对对象的属性等进行初始化
>非静态代码块可以调用静态的属性和静态的方法,或非静态的属性和非静态的方法
5. 执行顺序:由父及子,静态先行
6. 对属性可以赋值的位置:
①默认初始化
②显式初始化
③构造器中初始化
④”对象.属性“或“对象.方法”赋值
⑤代码块中赋值
执行先后顺序:① - ②/⑤ - ③ - ④
*/
public class BlockTest {
public static void main(String[] args) {
String desc = Person1.desc;
System.out.println(desc);
Person1 person1 = new Person1();
Person1 person2 = new Person1();
System.out.println(person1.age);
System.out.println(person2.age);
}
}
class Person1{
//属性
String name;
int age;
static String desc = "我是一个人";
//构造器
public Person1() {
}
public Person1(String name, int age) {
this.name = name;
this.age = age;
}
//static代码块
static{
System.out.println("Hello,static block");
desc = "我是一个爱学习的人";
}
//非static代码块
{
System.out.println("Hello,block");
age = 1;
}
//方法
public void eat(){
System.out.println("吃饭");
}
public static void info(){
System.out.println("我是一个快乐的人");
}
@Override
public String toString() {
return "Person1{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
final关键字
package com.oop.demo08;
/*
final关键字
1. final可以用来修饰的结构:类、方法、变量
2. final修饰类:此类不能被其他类所继承
比如:String类、System类、StringBuffer类
3. final修饰方法:此方法不能被重写
比如:Object类中getClass()方法
4. final修饰变量:此变量就称为“常量”
4.1 final修饰属性--可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化
4.2 final修饰局部变量--尤其是使用final修饰形参时,表名此形参是一个常量,赋值后只能使用,不能修改
5. static final用来修饰属性:全局常量
*/
public class FinalTest {
final int WIDTH = 0;
final int LEFT;
final int RIGHT;
// final int DOWN;
{
LEFT = 1;
}
public FinalTest(){
RIGHT = 2;
}
public FinalTest(int n){
RIGHT = n;
}
// public void setDOWN(int down){//final修饰属性不能通过方法赋值
// this.DOWN = down;
// }
public static void main(String[] args) {
}
}
final class FinalA{
}
//class B extends FinalA{
//
//}
class AA{
final public void show(){
}
}
//class BB extends AA{
// public void show(){//不能被重写
//
// }
//}