面向对象相关知识清单
面向对象
面向对象的三大特性:
1.封装
2.继承
3.多态
类与对象的概念(定义类,创建对象)(类=属性+方法)
类是对象具有共性事物的抽象描述,是在概念上的一个定义。
例如:假设把一个班级看做成一个类,那么班级中的任一一个同学为一个对象(对象是实际存在的个体)
类–>对象-----实例化的过程
对象–>类-----抽象的过程
对象和对象之间具有共同特征,但是每个特征所对应的具体值不一样
面向对象可以分为三个阶段:
OOA(面向对象的分析)
OOD(面向对象的设计)
OOP(面向对象的编程)
对象的创建和使用
在Java语言中,所有new出来的东西,统一放在堆(heap)中存储,无法直接对堆中数据进行访问,但可以通过引用来间接访问
引用保存的是内存地址,指向堆中的对象
//对象的创建和使用
public class OOTest01 {
public static void main(String[] args) {
//1.创建对象
//stu1是一个局部变量,这个局部变量stu1是Student类型,也就是一个引用类型
//stu1该局部变量称作引用,引用中保存的对象在堆中的内存地址
//通过“引用”去间接访问堆中的对象
Student stu1=new Student();
//一个类可以创建多个对象
//Student stu2=new Student();
//2.使用对象
//访问成员变量必须使用“引用.”
//赋值
stu1.id=15;
stu1.name="熊大";
stu1.age=“60”;
//读取过程
System.out.println("id="+stu1.id);
System.out.println("name="+stu1.name);
System.out.println("age="+stu1.age);
面向对象的封装性
面向对象的封装性指的是:
1.属性私有化(属性前有private关键字)
2.对外提供公开的setter and getter方法(set\get+属性名,属性名首字母大写)
创建Customer类
public class Customer{
//属性
private int age;//成员变量,实例变量,非静态变量
//set赋值
public void setAge(int _age){
if(_age<0){
System.out.println("年龄不合法");
return;
}
age=_age;
}
//get 读取
public int getAge(){ //成员方法必须使用引用.方式调用
return age;
}
}
测试
public class Test{
public static void main(String[] args){
//创建Customer对象
Customer c=new Customer();
//赋值
c.setAge(10);
//读取
System.out.println(c.getAge());
}
}
构造函数(构造方法,构造器,Constructor)
构造方法主要用来创建类的实例化对象,可以完成创建实例化对象的初始化工作,声明格式:
构造方法修饰词列表 类名 (方法参数列表)
关于java类的构造函数:
1.构造方法语法:
[修饰符列表] 构造方法名 (形式参数列表){
方法体;
}
2.构造方法的作用:
第一:创建对象
第二:给成员变量赋值(初始化成员变量)
3.构造方法如何调用?
new 构造方法名(实参); 在堆中开辟空间存储对象
4.成员变量到底什么时候赋值?
只有在调用构造方法的时候,才会给成员变量赋值
构造方法修饰词列表:public proteced private
(类的构造方法和普通方法一样可以进行重载)
构造方法的特点
1.构造方法名必须和类名一致
2.构造方法不具有任何返回值类型,即没有返回值,关键字void也不能加入,加入了就不是构造方法了,变成了普通方法
3.任何类都有构造方法,如果没有显示类的定义,系统会默认为该类定义一个默认的无参数构造器,如果显示定义了构造器,系统就不会创建默认的无参数的构造器了
定义一个User类
public class User{
//成员变量,属性,实例变量,非静态变量
String name;
int age;
//构造方法
User(){}
User(int _age){
age=_age;
}
User(String _name){
name = _name;
}
User(String _name,int _age){
name = _name;
age=_age;
}
}
测试
public class Test{
public static void main(){
//创建User对象
User u1=new User();
User u2=new User(20);
User u3=new User("熊大");
User u4=new User("熊二",16);
System.out.println(u2.age);
System.out.println(u3.name);
System.out.println(u4.name);
System.out.println(u4.age);
}
}
Java中内存的划分
this关键字
1.this是什么?
this是一个引用类型,在堆中每一个Java对象都有this,this保存的内存地址指向自身。this 关键字用来表示当前对象本身,或当前类的一个实例,通过this可以调用对象的所有方法和属性。
2.this可以用在哪些地方?
this可以用在成员方法中
this可以用在构造方法中
语法:this(实参);
必须出现在构造方法第一行
通过一个构造方法区调用另一个构造方法,达到代码重用。
this不可以用在静态方法中
this用在成员方法中
public class This01{
public static void main(String[] args){
Employee e=new Employee(6632,"小狗");
e.work();
Employee e1=new Employee(2580,"猫仔");
e1.work();
}
}
class Employee{
//Field
int empno;
String name;
//Constructor
Employee(){}
Employee(int _empno,String _ename){
empno=_empno;
ename=_ename;
}
//this用在成员方法中,谁去调用这个成员方法,this就代表谁,this指的就是当前对象
public void work(){
System.out.println(this.ename+"在工作");//this.可以省略
}
}
this用在构造方法中
public class This02{
public static void main(String[] args){
MyDate t=new MyDate();
System.out.println(t.year+"年"+t.month+"月"+t.day+"日");
}
}
//日期
class MyDate{
//Field
int year;
int month;
int day;
//Constructor
MyDate(){
this(2000,2,2);
}
MyDate(int _year,int _month,int _day){
year=_year;
month=_month;
day=_day;
}
}
this可以用来区分成员变量和局部变量
public class This03{
public static void main(String[] args){
Manager m1=new Manager("熊大");
Manager m2=new Manager();
m2.setName("熊二");
System.out.println(m1.getName());
System.out.println(m2.getName());
}
}
class Manager{
//Field
private String name;
//Constructor
Manager(){}
Manager(String name){
this.name=name;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;//this.省略
}
}
static关键字
1.static修饰的变量叫做静态变量
2.static修饰的方法叫做静态方法
3.static还可以定义静态语句块
演示static定义静态语句块
public class StaticTest01{
//静态语句块
//static定义的语句块在类加载阶段执行(在main方法执行之前),并且只执行一次,
//按照自上而下的顺序执行
static{
System.out.println("今天");
}
static{
System.out.println("你");
}
static{
System.out.println("学废了么");
}
public static void main(String[] args){
System.out.println("main方法执行");
}
}
演示实例语句块
1.每一次调用构造方法之前会执行一次
2.自上而下的顺序执行
以下代码的输出顺序为:
A
1
2
Test无参数构造方法执行
public class Test{
//静态语句块
static{
System.out.println("A");
}
//实例语句块
{
System.out.println("1”);
}
{
System.out.println("2”);
}
//Constructor
Test(){
System.out.println("Test无参数构造方法执行");
}
public static void main(String[] args){
//调用构造方法
new Test();
}
}
演示static修饰的静态方法
public class Test{
//成员方法
//成员方法必须使用“引用.”方式调用
/public void m1(){}
//静态方法
//可以使用“类名.”方式调用,也可以使用“引用.”,即使是“引用.”,底层还是类名.
//静态方法中不能直接访问非静态数据
//静态方法中不能使用this
public static void m2(){
System.out.println("m2..");
}
public static void main(String[] args){
Test t= new Test();
t.m1();
m2();
//静态方法正规的方式访问是“类名.”
//静态方法也能用“引用.”访问
t.m2();//编译阶段检查出t是Test类型,编译通过
//运行的时候,仍然使用Test.方式访问,该方法不需要对象
}
}
演示static修饰静态变量
什么时候变量声明成静态变量?
如果该属性所有的对象都有,并且这个属性的值是相同的,则该属性声明成静态变量(在类加载阶段赋值,并且只赋值一次)
public class Test{
public static void main(Striong[] args){
Animal a1=new Animal("猫",10);
Animal a2=new Animal("狗",20);
System.out.println(Animal.type);
Animal a3=null;
System.out.println(a3.type);//静态变量底层访问的时候一定使用 类名. 和对象无关,
//不会出现空指针异常
}
}
class Animal{
//Field
//成员变量(一个对象一份)
//成员变量在创建对象的时候初始化,并且存储在堆中的每一个对象中
String name;
int age;
//静态变量,被存储在方法区
//所有的Java对象共享这一份
//静态变量是类级别的,使用“类名.”方式访问
Static String type = "陆生";
//Constructor
Animal(String name,int age){
this.name = name;
this.age = age;
}
}
单例模式
什么是设计模式:设计模式是可以重复利用的解决方案。由GoF四人组在1995年提出。
设计模式分为三类:
1.创建型
2.结构性
3.行为型
单例模式的好处:
我们知道对象实例创建完成后,会放到堆中,如果堆中的实例过多,将会存在特别多的垃圾,这样会导致内存溢出等问题。使用单例模式后,只会创建一个实例,显著减少对象实例的个数,同时也会提高性能。
单例模式的缺点:单例模式的类型无法被继承。
单例模式纲领
1.构造方法私有化
2.对外提供一个公开的静态的获取当前类型对象的方法
3.提供一个当前类型的静态变量
单例模式分为两种:
1.饿汉式单例:(在类加载阶段就创建了对象)
2.懒汉式单例:(用到对象的时候才会创建对象)
实现懒汉式单例
public class Singleton{
//静态变量
private static Singleton s;
//将构造方法私有化
private Singleton(){}
//对外提供一个公开获取Singleton对象的方法
public static Singleton getInstance(){
if(s==null){
s=new Singleton();
}
return s;
}
}
实现饿汉式单例
public class Customer{
//类加载时只执行一次
private static Customer c = new Customer();
//构造方法私有化
private Customer(){}
//提供公开的方法
public static Customer getInstance(){
return c;
}
}
测试
public class Test{
public static void main(String[] args){
Customer c1=Customer.getInstance();
Customer c2=Customer.getInstance();
System.out.println(c1==c2);//true
}
}
继承(类与类只支持单继承)
继承最基本作用:代码重用
继承最重要的作用:方法可以重写
语法:
[修饰符列表] class 子类名 extends 父类名{
类体
}
一个类如果没有显示继承其他类,则默认继承Object类
父类
public class Dad{
public void study(){
System.out.println("学习");
}
public void feed(){
System.out.println("吃饭");
}
}
子类
public class Son extends Dad{
//所有父类的方法都可以继承过来
//该子类包含父类中的study()和feed()方法
public void sleep(){
System.out.println("睡觉");
Son.study();
Son.feed();
}
}
有关于方法
什么是方法?
方法就是一段代码片段,调用的时候可以重复利用。
定义方法的语法
[方法的修饰符列表] 方法的返回值类型 方法名 (方法的形式参数列表){
java语句;
}
1.[方法的修饰符列表] 是可选项
2.方法的返回值类型,可以实java语言中的任何一种数据类型(基本数据类型和引用数据类型)
3.如果该方法执行结束之后,并没有任何返回值,那么定义方法的时候,返回值类型写:void
4.方法名只要是合法的标识符即可
5.方法的形式参数列表,可以有参数,也可以没有参数,如果有多个参数列表的话,使用 , 隔开
6.如果一个方法的返回值类型不是void,那么在方法体中必须使用return语句来返回数据。
关于方法的调用(在static中使用类名. 的方式去调用)
public class MethodTest02 {
//入口
public static void main(String[] args) {
//在main方法中对sumInt方法进行调用,完成功能。
//注意:加有static的方法,调用的时候必须采用“类名”的方式调用。
MethodTest02.sumInt(10,20);
MethodTest02.sumInt(50,100);
}
//定义方法,完成两个整数的求和。
//注意:目前所有的方法定义成public static.
public static void sumInt(int a,int b) {
int c = a + b;
System.out.println(a + "+" + b + "=" + c);
}
}
public class MethodTest03 {
//入口
public static void main(String[] args) {
//方法调用
MethodTest03.m1(13,15);
MethodTest03.m2();
//调用m3
int retValue = MethodTest03.m3(100, 200);
System.out.println("计算结果是:"+retValue);
}
//方法的定义
//方法形式参数列表中起决定性作用的是参数的类型。
//参数的名字(局部变量的名字)是随意的只要是合法的标识符即可。
public static void println(String msg) {//String msg是方法的形式参数列表。
System.out.println(msg);
}
public static void m1(int a, int b) {
System.out.println(a+"+"+b+"="+(a+b));
}
public static void m2() {
System.out.println("呵呵");
}
//该方法有返回值,程序必须使用return语句返回值
public static int m3(int a,int b) {
int c=a+b;
return c;//程序执行到此处m3方法执行结束
//return语句下面不能再有其他代码,因为根本无法执行到。
//System.out.println("ABC");//编译无法通过。
}
}
在调用方法时省去类名(在调用方法时,如果在当前类可以省去类名)
public class MethodTest04 {
public static void main(String[] args) {
A.m1();
//Error:在当前类名中没有m1方法。
//m1();
MethodTest04.m2();
//前提:在当前类名中可以省
//类名可以省
m2();
}
public static void m2() {
System.out.println("m2...");
}
}
class A{
public static void m1() {
System.out.println("A's m1 method invoke!");
}
}
关于方法的重载(overload)
优点:
1.记忆更少的方法名,方便调用
2.代码更加美观
重载时需要的条件:
1.发生在同一个类中
2.方法名相同
3.参数列表不同(参数的类型、个数、顺序)
4.和返回值类型无关
5.和方法的修饰符列表无关
public class MethodTest08 {
public static void main(String[] args) {
System.out.println(Computes.sum(10,20));
System.out.println(Computes.sum(1.0,2.0));
System.out.println(Computes.sum(10L,20L));
}
public static void m1(int a) {}
public static void m1(double a) {}
public static void m2(int a,int b) {}
public static void m2(int a) {}
public static void m3(int a,double b) {}
public static void m3(double a,int b) {}
//以下两个m4方法并没有构成重载
//方法重复,错误的
//public static void m4(int a){}
//public static void m4(int b){}
//方法的重载和方法的返回值类型无关
/*
public static void m5() {}
public static void m5() {
return 100;
}
*/
//方法的重载和方法的修饰符列表无关
/*
static void m6(){}
public static void m6(){}
*/
}
class Computes{
public static int sum(int a,int b) {
return a + b;
}
public static double sum(double a,double b) {
return a + b;
}
public static long sum(long a,long b) {
return a + b;
}
}
关于方法的递归(方法的递归调用就是方法自身调用自身)
以下程序因为递归没有结束条件,所以一直压线,没有弹栈,导致栈内存中溢出错误!
public class RecursionTest01 {
//入口
public static void main(String[] args) {
m1();
}
public static void m1() {
m1();//java.lang.StackOverflowError
}
}
方法的覆盖(override)
1.什么时候进行方法的重写?
如果父类中的方法已经无法满足当前子类的业务需求,需要将父类中的方法重写
2.子类如果重写父类中的方法之后,子类对象一定调用的时重写之后的方法
3.发生在方法覆盖的条件:
第一:发生在具有继承关系的两个类之间
第二:必须具有相同的方法名,相同的返回值类型,相同的参数列表
第三:重写的方法不能比被重写的方法拥有更低的访问权限
第四:重写的方法不能比被重写的方法抛出更宽泛的异常
第五:私有的方法不能被覆盖
第六:构造方法不存在覆盖
第七:静态方法不存在覆盖
第八:覆盖指的是成员方法,和成员变量无关
public class Test{
public static void main(String[] args){
//创建子类对象
Cat c=new Cat();
//调用方法
c.move();
Animal a=new Animal();
a.move();
}
}
//父类
class Animal{
//成员方法
public void move(){
System.out.println("动物在移动");
}
}
//子类
class Cat extends Animal{
//Cat的move方法应该输出:猫在移动
//Animal中的move方法已经无法满足需求
//在Cat类堆move方法进行重写
public void move(){
System.out.println("猫在移动");
}
}
多态
Java语言中的向上转型和向下转型
1.向上转型(upcasting):子—>父 (自动类型转化)
2.向下转型(downcasting):父–>子 (强制类型转换)
注:无论是向上转型还是向下转型,两个类之间必须要有继承关系
以下代码演示多态
public class Animal{
//成员
public void eat(){
System.out.println("动物在吃东西");
}
}
public class Cat extends Animal{
//重写
public void eat(){
System.out.println("猫吃鱼");
}
}
public class Dog extends Animal{
//重写
public void eat(){
System.out.println("狗吃肉");
}
}
public class Test{
public static void main(String[] args){
//向上转型
//父类型引用指向子类型对象
//程序分为两个阶段:编译简短和运行阶段
//程序在编译阶段只知道a1是一个Animal类型
//程序在运行的时候堆中的实际对象是Cat类型
Animal a1=new Cat();
//程序在编译阶段a1被编译器看作是Animal类型
//程序在编译阶段a1引用绑定的是Animal类中的eat方法(静态绑定)
//程序在运行的时候堆中的对象实际上是Cat类型,而Cat已经重写了eat方法
//所以程序在运行阶段对象的绑定方法是Cat中的eat方法(动态绑定)
a1.eat();//猫吃鱼
//向下转型:强制类型转换
Animal a2=new Cat();
//执行move方法只能强制类型转换,需要加强制类型转换符
Cat c1=(Cat)a2;
c1.move();
//Animal a3=new Dog();向上转型
//强制类型转换
Cat c2=(Cat)a3;//java.lang.ClassCastException
//在做强制类型转换的时候程序存在风险
//避免风险,用instanceof
/*
用法:
1.instanceof运算符的运算结果是boolean类型类型
2.(引用 instanceof 类型) -->true/false
例如:(a instanceof Cat) 如果结果是true表示:a引用指向堆中的Java对象是Cat类型
*/
Animal a3=new Dog();
System.out.println(a3 instanceof Cat);//false
//推荐:在做向下转型的时候要使用instanceof
if(a3 instanceof Cat){
Cat c2=(Cat)a3;
}
}
}
多态的好处
1.使用多态可以使代码之间的耦合度降低
2.项目的扩展能力增强
测试
public class Animal{
public void eat(){
}
}
public class Cat extends Animal{
public void eat(){
Sytem.out.println("猫吃鱼");
}
}
public class Dog extends Animal{
public void eat(){
Sytem.out.println("狗吃肉");
public class Person{
public void feed(Animal a){
a.eat();
}
}
public class Test{
public static void main(String[] args){
//1.创建主人
Person p=new Person();
//2.创建宠物
Dog d=new Dog();
Cat c=new Cat();
//3.喂
p.feed(d);
p.feed(c);
}
}
super关键字
1.super不是引用类型,super中存储的不是内存地址,super指向的不是父类对象
2.super代表的是当前子类对象中的父类型特征
3.什么时候使用super?
子类和父类中都有某个数据,例如:子类和父类中都有name这个属性,如果要在子类中访问父类中的name属性,需要用到 super.
4.super可以用在什么地方?
第一:super可以用在成员方法中,不能用在静态方法中
第二:super可以用在构造方法中
语法:super(实参);
作用:通过子类的构造方法去调用父类的构造方法
语法规则:一个构造方法第一行如果没有this(…),也没有显示去调用super(…),系统默认调用super();
super(…)的调用只能放在构造方法第一行
super(…)和this(…)不能共存
super(…);调用了父类的构造方法,但是并不会创建父类对象。
在Java语言中,只要是创建Java对象,那么Object中的无参数构造方法就会执行
//父类
public class Employee{
String name="张三";
//成员方法
public void work(){
System.out.println("员工在工作!");
}
}
//子类
public class Manager extends Employee{
String name="李四";
//子类将父类中的work方法重写了
public void work(){
System.out.println("经理在工作");
}
//成员方法
public void m1(){
super.work();
System.out.println(this.name);//李四
System.out.println(name);//李四
System.out.println(super.name);//张三
}
}
super关键字用在构造方法中
public class Account{
//Field
private String actno;
private double balance;
//Constructor
public Account(){
//super();//默认存在
System.out.println("Account的无参数构造方法执行");
}
public Account(String actno,double balance){
this.actno=actno;
this.balance=balance;
}
public void setActno(String actno){
this.actno=actno;
}
public String getActno(){
return actno;
}
public void setBalance(double balance){
this.balance=balance;
}
public String getBalance(){
return balance;
}
}
public class DebitAccount extends Account{
//Field
//独特属性
private double debit;
//Constructor
public DebitAccount(){
//super();//默认存在
}
public DebitAccount(String actno,double balance,double debit){
//通过子类的构造方法去调用父类的构造方法,作用是:
//给当前子类对象中的父类型特征赋值
super(actno,balance);
thi.debit=debit;
}
public void setDebit(double debit){
this.debit=debit;
}
public double getDebit(){
return debit;
}
}
final关键字
final表示不可改变的含义
1.采用final修饰的类不能被继承
2.采用final修饰的方法不能被覆盖
3.采用final修饰的变量不能被修改
4.final修饰的变量必须显示初始化
5.如果修饰的引用,那么这个引用只能指向一个对象,也就是说这个引用不能再次赋值,但被指向的对象是可以修改的
6.构造方法不能被final修饰
7.会影响Java类的初始化final定义的静态常量调用时不会执行static代码块等相关语句,这是由JVM规定的
public class Test01 {
class A{
//final修饰的成员变量必须手动初始化
final int i=100;
//成员
final int k;
A(){
k=200;
}
}
//final修饰的成员变量一般和static连用
class MyMath{
//常量:Java规范中要求所有的常量“大写”
//常量:值不可再改变的变量
public static final double PI=3.14;
}
}
/*
深入final
final修饰的是引用类型,该引用不可再重新指向其他的Java对象
但是final修饰的引用,该引用指向的对象的属性是可以修改的
*/
public class Test02 {
public static void main(String[] args) {
final Customer c=new Customer("jack",15);
//c是final的,无法重新赋值
//但是c里边的属性可以重新赋值
c.name="ad";
c.age=25;
System.out.println(c.name);
System.out.println(c.age);
}
}
class Customer{
String name;
int age;
Customer(String name,int age){
this.name=name;
this.age=age;
}
}
抽象类
1.如何定义抽象类
class关键字前加abstract
2.抽象类无法被实例化
3.虽然抽象类无法被实例化,但是抽象类也有抽象方法,该方法是给与类创建对象用的
4.抽象类中可以定义抽象方法(抽象类可以没有抽象方法)
抽象方法的语法:在方法的修饰符列表中添加abstract关键字,并且抽象方法应该是以“;”结束,不能带有“()”
例如:public abstract void m1();
5.抽象类中不一定有抽象方法,但抽象方法必须出现在抽象类中
6.一个非抽象的类继承抽象类,必须将抽象类中的抽象方法覆盖,实现,重写
7.避免创建父类对象
8.避免调用无意义的父类方法
public abstract class A{
//Constructor
A(){
System.out.println("A...");
}
//抽象方法
public abstract void m1();
public static void main(String[] args){
//抽象类无法创建对象
//A a=new A();
A a=new B();
}
}
class B extends A{
public void m1(){}
B(){
super();//父类的构造方法虽然调用了,但是并没有创建父类对象
System.out.println("B...");
}
}
接口(interface)
接口也是一种引用类型,可以等同看作类
1.如何定义接口,语法:
[修饰符] interface 接口名 {}
2.接口中只能出现:常量,抽象方法
3.接口其实是一个特殊的抽象类,特殊在接口是完全抽象的
4.接口中没有构造方法,无法被实例化
5.接口和接口之间可以多继承
6.一个类可以实现多个接口
7.一个非抽象的类实现接口,需要将接口中所有的方法“实现”、“重写”、“覆盖”
8.所有属性都是public static final 修饰(public static final是可以省略的)
9.所有方法都是public修饰
10.不允许有静态方法
public interface A{
//常量必须用public static final 修饰
public static final String SUCCESS="success";
public static final double PI=3.14;
//public static final是可以省略的
byte MAX_VALUE=127;//常量
//抽象方法(接口中所有的抽象方法都是public abstract)
public abstract void m1();
//public abstract是可以省略的
void m2();
}
interface B{
void m1();
}
interface C{
void m2();
}
interface D{
void m3();
}
interface E extends B,C,D{
void m4();
}
class MyClass implements B,C{
public void m1(){}
public void m2(){}
public void m3(){}
public void m4(){}
}
接口的作用
1.可以使项目分层,所有层都可以面向接口开发,开发效率提高了
2.接口使得代码之间的耦合度降低,类似灯泡和灯口的原理,主板和内存条原理,“可插拔”
public interface CustomerService{
//定义一个推出系统的方法
void logout();
}
//接口实现类
public class CustomerServiceImpl implements CustomerService{
//对接口中的抽象方法进行实现
public void logout(){
System.out.println("成功退出系统");
}
}
//测试
public class Test{
public static void main(String[] args){
//要执行CustomerServiceImpl中的logout方法
//以下程序面向接口去调用
CustomerService cs=new CustomerServiceImpl();
//调用
cs.logout();
}
}
Object类
toString方法
/*
关于Object中的toString方法
SUN在Object类中设计toString方法的目的,返回Java对象的字符串表示形式
在现实的开发过程中,Object里边的toString方法已经不够用了
因为Object的toString方法实现的结果不满意
Object中的toString方法就是要被重写的
*/
public class toString {
public static void main(String[] args) {
//创建一个Object类型的对象
Object o1=new Object();
//调用toString方法
String oStr=o1.toString();
System.out.println(oStr);
//创建一个Person类型的对象
Person p1=new Person("熊大",50);
//调用toString方法
String pStr=p1.toString();
System.out.println(pStr);
Person p2=new Person("熊二",15);
System.out.println(p2.toString());
//print方法后面括号中如果是一个引用类型,会默认调用引用类型的toString方法
System.out.println(p2);
}
}
class Person{
String name;
int age;
Person(String name,int age){
this.name=name;
this.age=age;
}
//重写toString方法
//根据项目的需求而定
public String toString() {
return "Person[name="+name+",age="+age+"]";
}
}
equals方法
/*
* 关于Object中的equals方法
* Object中的equals方法:
* public boolean equals (Object obj){
* return (this==obj);
* }
*
* o1.equals(o2); o1是this,o2是obj
* ==两边如果是引用类型,则比较内存地址,地址相同则是true,反之为false
* Object中的equals方法比较的是两个引用的内存地址。
*
* Java对象中的equals方法的设计目的:判断两个对象是否一样。
*/
public class equalsTest01 {
public static void main(String[] args) {
Object o1=new Object();
Object o2=new Object();
boolean b1=o1.equals(o2);
System.out.println(b1);//false
Star s1=new Star(100,"黄晓明");
Star s2=new Star(100,"黄晓明");
Star s3=new Star(110,"黄晓明");
System.out.println(s1.equals(s2));//true
System.out.println(s2.equals(s3));//false
}
}
class Star{
//身份证号
int id;
//姓名
String name;
//Constructor
public Star(int id,String name) {
this.id=id;
this.name=name;
}
//Object中的equals方法比较的是内存地址
//在现实的业务逻辑上,不应该比较内存地址,应该比较内容
//所以Object中的equals方法也要重写
//根据需求规定重写equals方法
//需求规定:如果身份证号一致,并且名字也一致,则代表是同一个人
//s1.equals(s2);
public boolean equals(Object obj) {
if(this==obj) return true;
if(obj instanceof Star) {
Star s=(Star)obj;
if(s.id==id && s.name.equals(name)) {
return true;
}
}
return false;
}
}
finalize方法
/*
关于Object中的finalize方法
finalize方法什么时候调用?
1.finalize方法每个Java对象都没有
2.finalize方法不需要程序员去调用,由系统自动调用
3.Java对象如果没有更多的引用指向它,则该Java对象成为垃圾数据
等待垃圾回收器的回收,垃圾回收器在回收这个Java对象之前会自动
调用该对象的finalize方法
finalize方法是该对象马上就要被回收了,例如:需要释放资源,则可以在该方法中释放
*/
public class finalize {
public static void main(String[] args) {
People p1=new People();
p1=null;//没有引用在指向它,等待回收
//程序员只能“建议”垃圾回收器回收垃圾
System.gc();
}
}
class People{
//重写Object中的finalize方法
public void finalize() throws Throwable{
System.out.println(this+"马上就要被回收了");
//让引用再次指向该对象,该对象不是垃圾数据,不会被垃圾回收器回收
//Person p=this;
}
}
hashCode方法
public class hashCodeTest01 {
public static void main(String[] args) {
//hashCode方法返回的是该对象的哈希码值
//Java对象的内存地址经过哈希算法得出的int类型的数值
hashCodeTest01 t=new hashCodeTest01();
System.out.println(t.hashCode());
}
}
访问控制权限
/*
* 关于访问控制权限修饰符:修饰类,修饰方法,修饰变量
* private 只能在本类中访问
* default 缺省 本类,同一个包下,不同包下不行
* protected 本类,同一个包下,不同包下不行,但是子类中可以
* public 可以在任何位置访问
*/
public class User { //类User只能用public或者缺省方式
//protected修饰
protected String name;
//缺省 default修饰
int age;
}
class Test01{
public static void main(String[] args) {
User u=new User();
System.out.println(u.name);
System.out.println(u.age);
}
}
内部类
静态内部类
1.静态内部类可以等同看作静态变量
内部类重要作用:可以访问外部类中私有的数据
2.静态内部类可以直接访问外部类的静态数据,无法直接访问成员
public class OuterClass{
//静态变量
private static String s1="A";
//成员变量
private String s2="B";
//静态方法
private static void m1(){
System.out.println("static's m1 method execute!");
}
//成员方法
private void m2(){
System.out.println("m2 method execute!");
}
//静态内部类
//可以用访问权限的修饰符来修饰
//public protected private 缺省
//静态方法
static class InnerClass{
System.out.println(s1);
m1();
}
//成员方法
public void m4(){
System.out.prinln(s1);
m1();
}
}
public static void main(String[] args){
//执行m3
OuterClass.InnerClass.m3();
//执行m4
InnerClass inner=new OuterClass.InnerClass();
inner.m4();
}
成员内部类
1.成员内部类可以等同看作成员变量
2.成员内部类中不能有静态声明
3.成员内部类可以访问外部类所有的数据
public class OuterClass {
//静态变量
private static String s1="A";
//成员变量
private String s2="B";
//静态方法
private static void m1() {
System.out.println("static's m1 method execute!");
}
//成员方法
private void m2() {
System.out.println("m2 method execute!");
}
//成员内部类
//可以用访问控制权限的修饰符修饰
//public protected private 缺省
class InnerClass{
//静态方法
//public static void m3(){}
//成员方法
public void m4() {
System.out.println(s1);
m1();
System.out.println(s2);
m2();
}
}
//入口
public static void main(String[] args) {
//创建外部类对象
OuterClass oc=new OuterClass();
InnerClass inner=oc.new InnerClass();
inner.m4();
}
}
局部内部类
1.局部内部类等同于局部变量
2.局部内部类在访问局部变量的时候,局部变量必须使用final修饰
public class OuterClass {
//方法
public void m1() {
//局部变量
final int i=10;
//局部内部类
//局部内部类不能用访问控制权限修饰符修饰
class InnerClass{
//内部类不能有静态声明
//public static void m1(){}
//成员方法
public void m2() {
System.out.println(i);//10
}
}
//调用m2
InnerClass inner = new InnerClass();
inner.m2();
}
//入口
public static void main(String[] args) {
OuterClass oc=new OuterClass();
oc.m1();
}
}
匿名内部类
指的是类没有名字
public class Test {
//静态方法
public static void t(CustomerService cs) {
cs.logout();
}
//入口
public static void main(String[] args) {
//调用t方法
//t(new CustomerServiceImpl());
//使用匿名内部类的方式执行t方法
//整个这个“new CustomerService(){}”就是个匿名内部类
t(new CustomerService(){
public void logout() {
System.out.println("exit");
}
});
//匿名内部类的优点:少定义一个类
//缺点:无法重复利用
}
}
//接口
interface CustomerService{
//退出系统
void logout();
}
//编写一个类实现CustomerService接口
/*
class CustomerServiceImpl implements CustomerService{
public void logout(){
System.out.println("系统已经安全退出!");
}
}
*/