目录
类和对象(单例模式、继承、多态)
一、单例模式
(1)单例类只能有一个实例;
(2)单例类必须自己创建自己的唯一实例;
(3)单例类必须给所有其他对象提供这个实例。
场景:一个类可以定义无数个对象,但是只有一个实例。
1、饿汉式单例模式
package practise.test1030;
//饿汉式单利模式
class MySingleTon2{
private static MySingleTon2 singleTon = new MySingleTon2();
private MySingleTon2(){
System.out.println("MySingleTon2().init");
}
//提供一个全局的访问点
public static MySingleTon2 getInstance(){
return singleTon;
}
}
public class Test2 {
public static void main(String[] args) {
MySingleTon2 mySingleTon = MySingleTon2.getInstance();
MySingleTon2 mySingleTon2 = MySingleTon2.getInstance();
MySingleTon2 mySingleTon3 = MySingleTon2.getInstance();
MySingleTon2 mySingleTon4 = MySingleTon2.getInstance();
System.out.println(mySingleTon);
System.out.println(mySingleTon2);
System.out.println(mySingleTon3);
System.out.println(mySingleTon4);//地址相同
}
}
2、懒汉式单例模式
package practise.test1030;
//懒汉式单利模式
class MySingleTon{
private static Object lock = new Object();
private static MySingleTon singleTon = null;
private MySingleTon(){
System.out.println("MySingleTon().init");
}
//提供一个全局的访问点
//可重入函数:线程安全的函数 静态条件 临界区代码段 原子性操作 加锁
public static MySingleTon getInstance(){
//1
/**
* 原子操作
* 多进程时,第一个进程还未来得及new一个对象,singleTon==null
*/
if(singleTon == null){
singleTon = new MySingleTon();
}
//2
//单线程浪费空间
synchronized (lock){
if(singleTon == null){
singleTon = new MySingleTon();
}
}
//3
//多线程时至少执行两次
if(singleTon == null){
synchronized (lock){
singleTon = new MySingleTon();
}
}
//4 双重检验 (double-checked locking)
if(singleTon == null){
synchronized (lock){
if(singleTon == null){
singleTon = new MySingleTon();
}
}
}
return singleTon;
}
}
public class Test1 {
public static void main(String[] args) {
MySingleTon mySingleTon = MySingleTon.getInstance();
MySingleTon mySingleTon2 = MySingleTon.getInstance();
MySingleTon mySingleTon3 = MySingleTon.getInstance();
MySingleTon mySingleTon4 = MySingleTon.getInstance();
System.out.println(mySingleTon);
System.out.println(mySingleTon2);
System.out.println(mySingleTon3);
System.out.println(mySingleTon4);//地址相同
}
}
3、静态内部类实现单例模式
package practise.test1030;
//静态内部类实现单利模式
//只有访问静态内部类的时候,才会创建对象
class MySingleTon3{
private MySingleTon3(){
}
private static class SingleTon{
private static MySingleTon3 single = new MySingleTon3();
}
public static MySingleTon3 getInstance(){
return SingleTon.single;
}
}
public class Test3 {
public static void main(String[] args) {
MySingleTon3 single = MySingleTon3.getInstance();
MySingleTon3 single2 = MySingleTon3.getInstance();
MySingleTon3 single3 = MySingleTon3.getInstance();
MySingleTon3 single4 = MySingleTon3.getInstance();
System.out.println(single);
System.out.println(single2);
System.out.println(single3);
System.out.println(single4);
}
}
二、继承
继承是一种机制,可以进行代码的重用。在JAVA中,所有的继承都是公有继承。子类比超类拥有的功能更加丰富。
基类(超类):
子类(派生类):
在通过扩展类定义子类的时候,仅需要指出子类与超类的不同之处。所以在设计类的时候应该将通用的方法放在超类,而将具有特殊用途的方法放在子类当中。
在子类中可以增加域、增加方法或覆盖超类的方法,但是绝对不能删除继承的任何域和方法。
注:
(1)关键字this作用:
1、引用隐式参数;
2、调用该类其他的构造器。
(2)super关键字作用:
1、调用超类的方法;
2、调用超类的构造器。
在调用构造器的时候,这两个关键字的使用方式很相似:调用构造器的语句只能作为另一个构造器的第一条语句出现。构造参数既可以传递给本类(this)的其他构造器,也可以传递给超类(super)的构造器。
package practise.test1030;
//继承
/**
* super关键字:
* super();——调用基类的构造函数
* super.data——访问基类的数据成员
* super.func()——调用基类的成员方法
*/
/**
* 基类
*/
class Base{
public int ma;
public Base (int ma){
this.ma = ma;
}
//Base的静态代码块
static {
System.out.println("Base.static{}");
}
//Base的实例代码块
{
System.out.println("Base.instance");
}
public void fun(){
System.out.println("Base.fun()");
}
public static void fun2(){
System.out.println("Base.fun2()");
}
}
/**
* 派生类
* 继承父类除构造函数外的所有属性
* 派生类构造对象的初始化顺序
* 基类静态
* 派生类静态
* 基类实例
* 基类构造方法
* 派生类实例
* 派生类构造方法
*/
class Derieve extends Base {
private int mb;
public Derieve(int a,int b){
super(a);//必须放在第一行
this.ma = ma;
}
//Base的静态代码块
static {
System.out.println("Base.static{}");
}
//Base的实例代码块
{
System.out.println("Base.instance");
}
public void fun(){
System.out.println("Base.fun()");
}
public static void fun2(){
System.out.println("Base.fun2()");
}
}
//ERROR
/**
* 继承了ma,没有继承构造函数,
* 如何构造基类的数据成员???(调用基类的构造函数)
*/
/*class Derieve extends Base{
private int mb;
}*/
/**
* ERROR
* 派生类的构造函数只能构造派生类的数据成员,不能构造基类的数据成员
*
class Derieve extends Base {
private int mb;
public Derieve(int a,int b){
//ERROR ma = a;
this.mb = mb;
}
}*/
public class Test4 {
public static void main(String[] args) {
Base base = new Base(100);
Derieve derieve = new Derieve(111,222);//new对象 1、分配类存 2、
/**
* JAVA中只支持向上继承
*/
base = derieve;
/**
* 基类和派生类之间的相互赋值
*/
/**
* 重载:overloade:函数名相同,参数列表不同,和返回值没关系
* 并不一定是在同一个类当中,在继承关系上也能构成重载
* 重写(覆盖)overwrite;函数名相同,参数列表相同,函数返回值相同
* 返回值不同能否构成重载:???
* 遵守协变类型——JAVA编程思想
*/
}
}
问题一:派生类继承了父类除构造方法外的所有属性。
问题二:super关键字:
super关键字:
(1)super();——调用基类的构造函数
(2)super.data——访问基类的数据成员
(3)super.func()——调用基类的成员方法
问题三:派生类构造对象的初始化顺序?
(1)基类静态;
(2)派生类静态;
(3)基类实例;
(4)基类构造方法;
(5)派生类实例;
(6)派生类构造方法。
package practise.test1030;
//(public)基类的数据成员在派生类中的访问权限
class Base1{
public int ma;
// public Base (int ma){
// this.ma = ma;
// }
//Base的静态代码块
static {
System.out.println("Base.static{}");
}
//Base的实例代码块
{
System.out.println("Base.instance");
}
public void fun(){
System.out.println("Base.fun()");
}
public static void fun2(){
System.out.println("Base.fun2()");
}
}
//class Derieve1 extends Base {
//
//}
public class Test5 {
public static void main(String[] args) {
}
}
问题四:基类数据成员在派生类当中的访问权限:
同包子类 | 同包非子类 | 不同包子类 | 不同包非子类 | |
public | 可以 | 可以 | 可以 | 可以 |
private | / | / | / | / |
proctected | 可以 | 可以 | 可以 | / |
默认权限 (包访问权限) | 可以 | 可以 | / | / |
问题五:重载和重写(覆盖):
(1)重载:overloade:函数名相同,参数列表不同,和返回值没关系。
注:并不一定是在同一个类当中,在继承关系上也能构成重载 。
(2)重写(覆盖)override:函数名相同,参数列表相同,函数返回值相同。
三、多态
多态:基类引用,引用了派生累对象,并且和派生类有同名的覆盖方法。
JAVA实现多态有三个必要条件:继承、重写、向上转型。
(1)继承:在多态中必须存在有继承关系的子类和父类;
(2)重写:子类对父类中的某些方法进行重新定义,在调用这些方法时就会调用子类的方法;
(3)向上转型:在多态中,只有将子类的引用赋给父类对象,才能够调用父类的方法和子类的方法。
问题六:构造函数内,能不能发生多态?
能
问题七:动多态和静多态的理解:
(1)动多态:发生在运行的时候(重载);
(2)静多态:发生在编译的时候(重写).
在JAVA只有两种方式可以实现多态:继承和实现接口。