单例定义,写法
单例模式: 在程序运行其间,保存类对象只会创建一次(确保只有一个实例)
实现步骤:
私有化构造方法
提供本类的实例对象(好多种)
向类的外部提供一个方法,获取类的对象
为什么使用单例:1.能避免实例重复创建 2.应用于避免存在多个实例引起程序逻辑错误的场合3.较节约内存
单例写法案例
public class Demo{
public static void main(String[] args) {
Singleton tv1 = Singleton.getInstance2("张三");
Singleton tv2 = Singleton.getInstance2("李四");
System.out.println(tv1 == tv2);//true//比较的是内存地址
tv2.speak();//张三
}
}
class Singleton {
String name;
//1.私有化构造方法
private Singleton(String name) {
this.name = name;
}
//2.提供本类的对象
private static Singleton singleton1;
//写法一:同步懒汉式,3.向外部提供可访问的方法,并返回当前类的对象
public synchronized Singleton getInstance1(String name) {
if (singleton1 == null) {
singleton1 = new Singleton(name);
}
return singleton1;
}
//写法二:优化后的懒汉式,方法一中的同步冗余,3.向外部提供可访问的方法,并返回当前类的对象
public static Singleton getInstance2(String name) {
if (singleton1 == null) {
synchronized (Singleton.class) {
if (singleton1 == null) {
singleton1 = new Singleton(name);
}
}
}
return singleton1;
}
//写法三:饿汉式2.提供本类的对象
private static Singleton singleton3 = new Singleton("default");
//3.向外部提供可访问的方法,并返回当前类的对象
public static Singleton getInstance3() {
return singleton3;
}
//写法四:内部类
/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例没有绑定关系,
* 而且只有被调用到才会装载,从而实现了延迟加载
*
private static class SingletonHolder {
//2.提供本类的对象
private static final Singleton instance = new Singleton("default");
}
//3.向外部提供可访问的方法,并返回当前类的对象
public static Singleton getInstance4() {
return SingletonHolder.instance;
}
public void speak() {
System.out.println(name);
}
}
super 、this关键字
方法的重写:首先存在继承关系,然后方法名、参数、返回数据类型都与父类中方法名和参数相同。父类的私有方法不能被重写,静态只能覆盖静态。
this和super的使用
this
this 代有当前类的引用,可以通过this.成员形式来访问成员变量和方法,可以通过this() 来调用本类的其它构造方法,但必须在第一行
super
super:代表是父类的数据空间,并不是一个引用,因此没有对象可以指向可以通过 super.父类成员来访问父类的成员变量和成员方法;也可以通过super()来调用父类的构造方法,如果父类不存在无参的构造方法;在子类中必须调用super(),来指明初始化父类成员变量的构造方法,而且必须在第一行 。
注: super() 和 this()不能同时出现,this和super不能出现静态成员方法中
案例
public class Demo {
public static void main(String[] args){
Parent parent=new Child(); //多态
parent.say("您好");//父类说...您好
//子类说...您好
parent.print(); //父类打印...
}
}
class Parent {
public void say(String msg) {
System.out.println("父类说..." + msg);
}
public static void print() {
System.out.println("父类打印...");
}
}
class Child extends Parent {
//重写父类的方法可以扩展功能
public void say(String msg) {
super.say(msg); //调用父类的成员方法
System.out.println("子类说..." + msg);
}
public static void print() { //重写父类的静态方法时,只能以静态的方式覆盖
//super.print(); //this和super不能出现在静态成员方法中
System.out.println("子类打印...");
}
}
final关键字
final(C++ const): 最终的,修饰类、成员方法、成员变量、局部变量。
注意:
1、final修饰的类,不能被继承
2、final修饰的方法,不能被重写
3、final修饰的成员变量(局部变量),不能被修改
4.String类就是final 修饰的类
final案例
public class Demo {
public static void main(String[] args) {
Circle c = new Circle(5);
System.out.println(String.format("%.2f", c.area()));
}
}
final class Test1 { //这是一个最终的类
}
/*
class C_Test extends Test1{ //不能继承final类
}
*/
class Test2 {
public final void area() { //final修饰的方法不能被子类重写
}
}
class B_Test2 extends Test2 {
final int a = 10;
public void area(final int w, final int h) {
//a=90;//变量不能被修改
//w=w*h;
final Test2 t2 = new Test2();
//final 修饰的引用不能再指向其它对象
//t2=new Test2(); //出错
}
}
//求圆的面积 s=PI*r*r
class Circle {
public static final double PI = 3.1415;
private int radius; //半径
public Circle(int radius) {
this.radius = radius;
}
public double area() {
return PI * radius * radius;
}
}
抽象类 abstract class
abstract: 抽象的,包含抽象方法的类叫抽象类,abstract修饰的类;抽象类也是一个类,只不过没有足够的信息来描述某一事物行为的方法;特点:
1、抽象类不能创建对象,因为其中包含了未实现的抽象方法
2、继承抽象类的子类,如果没有实现抽象方法,则这个类也是抽象类
注意:
抽象类一定是父类,不然没有存在的意义。
抽象类是有构造方法,用于初始化类中的成员变量
抽象类和普通类区别
相同点: 都是类,可以被继承
不同点:抽象类不可以创建对象,普通类可以创建对象;抽象类可以包含抽象方法,普通类不能包含抽象方法
另,abstract不能与以下关键字组合使用:
final: final修饰的类不能被继承,abstract类必须要被继承(不然没意义)
static: 静态方法可以直接通过类名被调用,抽象方法不能被调用
private: 私有方法不能被重写,抽象方法必须被重写
案例
public class Demo {
public static void main(String[] args) {
//Circle1 c=new Circle1(6); //不能创建抽象类的对象
Rectangle r=new Rectangle(8,10);
System.out.println(r.area());//80.0
}
}
abstract class Shape{
public abstract double area();
}
abstract class Circle1 extends Shape{
public static final double PI=3.14;
private int radius;
public Circle1(){}
public Circle1(int radius){ this.radius=radius;}
public abstract double area();
}
class Rectangle extends Shape{
private int width;
private int height;
public Rectangle(int width,int height){
this.width=width;
this.height=height;
}
public double area(){ //实现抽象方法
return width*height;
}
}
abstract class Test3{ //注:抽象类中可以不存在抽象方法
}
class C_Test3 extends Test3{
}
interface 接口
定义格式
interface 接口名{ 全局常量; 抽象方法; }
特点
1、 接口可以实现多继承
2、 接口主要用于被实现,接口中的所有方法,在子类中必须全部实现
3、在定义接口实现类的时,使用implements关键字,而且可以多实现
扩展
类和类是继承关系;类和接口是实现关系;通过继承可以得到继承体系统中基本功能;通过实现可以得到除继承之外的额外功能;注: 一个可以存在继承关系同时也可以存实现关系
案例
public class Demo{
public static void main(String[] args) {
System.out.println(AllAnimalListener.type); //可以通过接口名直接访问全局变量//动物
//AllAnimalListener all=new AllAnimalListener(); //接口不能创建对象
Listener listener = new Animal();
listener.walk();//动物在走...
AllAnimalListener animalListener = new Animal();
animalListener.run();//最佳最近调用原则:多态性中体现//动物在跑...
}
}
interface Listener {
//声明全局常量
void walk();
}
interface CatListener {
void talk();
}
//接口的多继承,因为所有接口中方法都没有实现,不会存在调用的不确定性问题
interface AllAnimalListener extends CatListener, Listener {
static final String type = "动物";
void run();
}
class Animal implements AllAnimalListener, CatListener, Listener { //一个类可实现多个接口
//必须要实现或重写接口的方法 CatListener
@Override
public void talk() {
System.out.println(type + "在说话...");
}
//必须要实现或重写接口的方法 Listener
@Override
public void walk() {
System.out.println(type + "在走...");
}
//必须要实现或重写接口的方法 AllAnimalListener
@Override
public void run() {
System.out.println(type + "在跑...");
}
}
Java多态
对象的多态性: 多种形态,父类类型的引用指向子类对象,多态的前提:存在继承或实现关系
class 动物{
public void eat(){}
}
class 猫 extends 动物{
}
常态: 猫看成是猫 猫 c=new 猫();
多态: 猫是动物 动物 d=new 猫(); //第一种方式体现多态
void 方法名(动物 d){ //第二种方式体现多态
d.eat();
}
动物 方法名(int type){ //第三种方式体现多态
if(type==1){
return new 猫();
}
return new 狗();
}
多态的弊端
只能使用父类中定义的方法,并且子类必须重写父类中的方法
多态的好处
1.有继承或者实现接口的关系
2.重写或者实现父类(接口)的方法
3.父类指针指向子类对象
多态案例
public class Demo {
public static void main(String[] args) {
Cat cat = new Cat();//常态
cat.eat();//猫吃鱼
cat.catchMouse();//猫抓老鼠
Animal1 a1 = new Cat(); //多态,第一种方式
//a1.eat();
//a1.catchMouse();//出错,因为父类中没有声明此方法
Animal1 a2 = new Dog();//多态
//a2.eat();
eat(a1);//猫吃鱼
//小猫正在吃。。。。
eat(a2);//狗吃骨头
//小狗正在吃。。。。
}
public static void eat(Animal1 animal) { //第二种方式体现多态性
animal.eat(); //调用是Animal实际对象的方法,实际对象可能是Cat、Dog的类对象
//通过instanceof关键字判断对象是哪一种类型的对象
if (animal instanceof Cat) {
System.out.println("小猫正在吃。。。。");
} else {
System.out.println("小狗正在吃。。。。");
}
}
}
abstract class Animal1 {
public abstract void eat(); //虚方法
}
class Cat extends Animal1 {
public void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
class Dog extends Animal1 {
public void eat() {
System.out.println("狗吃骨头");
}
public void kanjia() {
System.out.println("看家");
}
}
向上,向下转型
多态第三种体现方式,向上转型: 子类类型向父类类型转换(自动--多态的体现);向下转型: 当子类中扩展的方法被调用时,需要将对象转成子类类型对象
案例
/**
* 注意: 为了减少错误,在强转之前,可以通过instanceof判断对象是否为某一种类型
*/
public class Demo{
public static void main(String[] args) {
Animal2 a1 = new Cat1(); //向上转换,子类对象转成父类对象
eat(a1);//猫吃鱼
//小猫正在吃。。。。
// 猫抓老鼠
Animal2 a2 = newAnimal(Animal2.TYPE_DOG);
eat(a2);//狗吃骨头
//小狗正在吃。。。。
//看家
}
public static void eat(Animal2 animal) { //第二种方式体现多态性
animal.eat(); //调用是Animal实际对象的方法,实际对象可能是Cat、Dog的类对象
//通过instanceof关键字判断对象是哪一种类型的对象
if (animal instanceof Cat1) {
System.out.println("小猫正在吃。。。。");
//需要调用Cat中扩展的方法
Cat1 c = (Cat1) animal; //向下转型,父类对象向子类对象转型
c.catchMouse();
} else {
System.out.println("小狗正在吃。。。。");
Dog1 d = (Dog1) animal;
d.kanjia();
}
}
//第三种体现多态性,根据类型创建某一动物的对象
public static Animal2 newAnimal(int type) {
if (type == Animal2.TYPE_CAT) {
return new Cat1();
} else if (type == Animal2.TYPE_DOG) {
return new Dog1();
}
return null;
}
}
abstract class Animal2 {
public static final int TYPE_CAT = 1;
public static final int TYPE_DOG = 2;
public abstract void eat(); //虚方法
}
class Cat1 extends Animal2 {
public void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
class Dog1 extends Animal2 {
public void eat() {
System.out.println("狗吃骨头");
}
public void kanjia() {
System.out.println("看家");
}
}
接口的多态体现
接口是一种引用数据类型,定义接口的引用指向到接口实现类对象, 则是接口体现多态的方式
/**
* 接口中的多态
* 接口与多态
*
*/
public class Demo {
public static void main(String[] args) {
Listen l1 = new Animal3(); //接口的多态
l1.walk();//动物在走
l1.music();//动物在唱歌
Listen l2 = new Person();
l2.walk();//人在走
l2.music();// 人在唱歌
}
}
interface Listen {
void music();
void walk();
}
class Animal3 implements Listen {
@Override
public void music() {
System.out.println("动物在唱歌");
}
@Override
public void walk() {
System.out.println("动物在走");
}
}
class Person implements Listen {
@Override
public void music() {
System.out.println("人在唱歌");
}
@Override
public void walk() {
System.out.println("人在走");
}
}
多态中的调用
多态中成员特点
成员变量: 能访问哪些成员变量,编译和运行时都看父类
成员方法: 访问哪些方法,编译时看父类,其运行结果要看子类
静态成员: 都看父类
案例
public class Demo{
public static void main(String[] args) {
Parent1 parent1 = new Child1();
System.out.println("num->" + parent1.num); //成员变量的结果:在编译和运行都看父类//num->20
parent1.say();//运行哪一个方法,编译时看父类,运行时看子类//Child1 say()
parent1.fun();//运行哪一个方法:(静态)编译和运行时都看父类//Parent1 static fun()
Child1 child1 = (Child1) parent1;
System.out.println("num->" + child1.num);//num->50
child1.say();//Child1 say()
child1.fun();//Child1 static fun()
}
}
class Parent1 {
int num = 20;
public void say() {
System.out.println("Parent1 say()");
}
public static void fun() {
System.out.println("Parent1 static fun()");
}
}
class Child1 extends Parent1 {
int num = 50;
public void say() {
System.out.println("Child1 say()");
}
public static void fun() {
System.out.println("Child1 static fun()");
}
}