Java基础复习(四)各种关键字,单例设计模式,基本类,以及内部类

final关键字

  1. 被final修饰的内容是无法再被改变的。
  2. final修饰的类不能有子类,即不能被继承
  3. 修饰成员变量时,变量是一个终值,不能再被改变,定义时需要赋初始值。
  4. 修饰局部变量时,也是一个终值,不能再被改变。
  5. final修饰的方法不允许被重写。

abstract关键字

  1. 抽象方法,抽象类
  2. 声明:不写函数体的函数,可以叫声明。
  3. 在继承中,提取父类方法时,每个子类都要实现该抽象方法,有函数体。父类不能决定子类中的实现方法。父类中只要写声明就好。(负责制定一个规则,内容自己去实现)
  4. 抽象方法:将方法的实现交给子类,只有方法声明的方法叫抽象方法,拥有抽象方法的类叫抽象类。
  5. 抽象类不一定有抽象方法,有抽象方法的一定是抽象类。
  6. 继承了抽象类的子类一定要实现抽象方法,若不实现就将自己也声明成抽象的。
  7. 抽象类不能实例化(不能直接创建对象),必须要通过子类实现,即抽象类一定有子类

比较final,abstract,static,private

不能与abstract同时存在的关键字:

  1. final:被final修饰的类不能有子类,方法不能重写,abstract修饰的类必须有子类,且方法必须被重写。
  2. static:static修饰的方法可以直接被类名调用,abstract必须通过子类实现,static修饰的方法跟随着字节码文件的出现而出现,出现的时间早于对象创建的时间。
  3. private:修饰的方法不能重写,abstract修饰的方法必须被重写。
  4. 抽象类中可以没有抽象方法,但是有抽象方法的类必须要被abstract修饰,即必为抽象类。
  5. 抽象方法没有方法体,只是抽象声明。

接口:interface

  1. 一般接口中不写成员变量,只写方法–只写规则,又将接口称为方法列表
  2. 让实现它的类去实现方法列表中的全部方法。
  3. 使用implements。
  4. 父类与接口的功能如何分配:一般父类中放的是主要功能,接口中放的是额外的功能,接口作为父类的补充.
  5. 接口不能创建对象,接口和接口之间可以有继承关系,只能是多继承。
  6. 从jdk1.7开始,以后的接口中可以有方法的实现,但是方法必须使用static或default修饰
  7. 如果一个类实现两个接口,这两个接口同时有相同的抽象方法,在类中只需要重写一次这个方法。
    ​ 如果接口中有default修饰的方法不需要重写。
    ​ 如果两个接口里的方法名相同都是default方法,里面的方法体不同,在类中需要重写该方法。
    ​ 如果两个接口中方法名,参数都相同的方法,一个接口是抽象方法,另一个是default修饰有方法体。这时该类也必须重写该方法。

接口(interface)和abstract类的区别

1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
4.抽象类中的抽象方法的访问类型可以是publicprotected和(默认类型,虽然eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
5. 抽象类中可以包含静态方法,接口中不能包含静态方法
6. 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。
7. 一个类可以实现多个接口,但只能继承一个抽象类。

设计模式

  1. 前人总结出来的对一些常见问题的解决方案,后人直接拿来用即可。
  2. 常用的设计模式:单例,工厂,代理,适配器,装饰,模板,观察者等,一共23种

单例设计模式

  1. 只允许有一个对象,需要建立一个单例类来描述

  2. 全局的访问点,通过static来实现,

  3. 作用:传值,作为全局的访问点

  4. 好处:可以让两个对象在完全没有关系的前提下,实现值的传递,降低了耦合性,提高了内聚性

  5. 如何做到低耦合高内聚:在处理类与类关系的时候,让类之间的关系越紧密耦合性越高,内聚性越低.反之,关系越松散耦合性越低,内聚性越高.

  6. 在单例中,一般只有向外提供S的方法是静态的,其他的都非静态的。
    在这里插入图片描述
    单例代码

    package test;
    
    /*
        饿汉式
       在定义SingleInstance成员变量时完成赋值。
     */
    class SingleInstance1{
        //2.在单例类的内部创建一个当前类的静态的私有化的对象
        //只有饿汉式可以加final
        private final static SingleInstance1 s = new SingleInstance1();
       //1.创建构造方法并且私有化
        private SingleInstance1()
        {
        }
        //3.通过公共的静态的方法将singleInstance对象提供出去
        public static SingleInstance1 getSingleInstance(){
            return s;
        }
    
        //功能区
        int num;
    
        public void test()
        {
    
        }
    
    }
    
    /*
        懒汉式
     */
    class SingleInstance2{
    
        //1.创建私有化的构造方法。
        private SingleInstance2(){}
        //2.在单例类的内部创建一个当前类的静态的私有化的对象
        private static SingleInstance2 s = null;
        //3.通过公共的静态的方法将singleInstance对象提供出去
        public static SingleInstance2 getSingleInstance()
        {
            if(s == null)
            {
                s = new SingleInstance2();
            }
                return s;
        }
    }
    public class demo2 {
        public static void main(String[] args) {
            SingleInstance1 s1 = SingleInstance1.getSingleInstance();
            SingleInstance1 s2 = SingleInstance1.getSingleInstance();
            System.out.println(s1 == s2);//true,说明用户只能获取一个唯一的对象
    
            SingleInstance2 s3 = SingleInstance2.getSingleInstance();
            SingleInstance2 s4 = SingleInstance2.getSingleInstance();
            System.out.println(s3 == s4);
    
            //传值:
            //实例:有一个A类和一个B类,A类中有一个变量num1,B类中有一个变量num2
            //创建A类的对象a,给变量赋值num1=4 ,创建B类的对象b,要实现的功能:将num1的值传给num2
            //直接传值:不建议使用
            A a = new A();
            B b = new B();
    
            //b.num2 = a.num1;
            //通过参数赋值
            //b.bText(a);
    
            //通过单例传值
            a.singleA();
            b.singleB();
        }
    }
    
    class A{
        private int num1 = 4;
        public int getNum1() {
            return num1;}
        public void setNum1(int num1) {
            this.num1 = num1;}
        //用于单例
        public void singleA(){
            SingleInstance1 singleInstance = SingleInstance1.getSingleInstance();
            singleInstance.num = num1;
            System.out.println(num1);
        }
    }
    class B{
        private int num2;
    
        public void bText(A a) {
            num2 = a.getNum1();
        }
        //用于单例
        public void singleB(){
            SingleInstance1 singleInstance = SingleInstance1.getSingleInstance();
            num2 = singleInstance.num;
            System.out.println(num2);
        }
    }
    

Runtime类

  1. 每个Java应用程序都有一个Runtime类实例,使应用程序能够与其运行的环境相连接。

  2. 可以通过getRuntime方法获取当前运行时间,应用程序不能创建自己的Runtime类实例

    Runtime runtime = Runtime.getRuntime();
    		//默认的单位是字节
    		System.out.println(runtime.freeMemory()/1024./1024.);//空闲的内存量
    		System.out.println(runtime.totalMemory()/1024./1024.);//返回的JVM的使用的总内存量
    		System.out.println(runtime.maxMemory()/1024./1024.);//可用的最大内存量
    

多态

  1. 多态:一种事物的多种形态. :狗 == 动物 == 生物 花 == 植物 == 生物 人== 高等动物 == 动物

  2. 继承是多态的前提

  3. 当父类与子类有同名属性或方法时

    • 成员变量:编译的时候能不能访问看父类,运行的时候也看父类
    • 成员方法:编译的时候能不能访问看父类,运行的时候看子类
    • 静态成员方法:编译运行都看父类
  4. 程序运行分成三个阶段:预编译,编译,运行

    • 预编译:程序打开的时候,活儿已经干完了.(预处理命令 #define)

      • 编译:从打开程序开始到点击左上角的三角之前—只能识别=前面的引用类型,不会识=后面的对象

      • 运行:从点击三角开始—真正的识别对象,对象开始干活儿

      • 实现动态的手段:动态类型,动态绑定,动态加载

      • 动态加载:我们在编译阶段不能确定具体的对象类型,只有到了运行阶段才能确定真正的干活儿的对象.

      • 实例

        public class Demo9 {
        	public static void main(String[] args) {
        		//总结:优点:可以提高代码的扩展性,使用之前定义好的功能,后面直接拿来使用,不用再创建新的方法.实例在Demo9
        		Dog dog = new Dog();
        		Cat cat = new Cat();
        		Pig1 pig = new Pig1();
        		Animal animal = new Animal();
        		feedAnimal(dog);
        		feedAnimal(cat);
        		feedAnimal(pig);
        	}
        	
        	//喂狗,喂猫,喂动物
        	public static void feedAnimal(Animal animal) {//animal = dog = new Dog()   多态
        		animal.eat();
        	}
        }
        
        class Animal{
        	public void eat() {
        		System.out.println("动物吃");
        	}
        }
        
        class Dog extends Animal{
        	@Override
        	public void eat() {
        		System.out.println("狗吃骨头");
        	}
        }
        
        class Cat extends Animal{
        	@Override
        	public void eat() {
        		System.out.println("猫吃");
        	}
        }
        
        class Pig1 extends Animal{
        	public void eat() {
        		System.out.println("猪吃");
        	}
        }
        

转型:

  1. 向上转型:相当于是自动类型转换,多态本身就是向上转型。

    Person1 person1 = new Student1();

  2. 向下转型:相当于强制类型转换

  3. 作用:解决多态中无法调用子类特有属性的缺点

  4. Student1 student121 = new Person1();
    1.这是不是父类的引用指向子类的对象,不是向上转型.使用子类的引用指向父类的对象是错误的.
    2.这里不是多态,所以不是向下转型
    

instanceof

  1. 这是一个运算符

  2. 构成:对象 instanceof 类或者类的子类

  3. 原理说明:确定当前的对象是否是后面的类或者子类的对象,是返回true,不是false

  4. 作用:进行容错处理,增加用户体验

  5. instanceof的前后必须有继承关系

  6. 代码实例

    public class Demo11 {
    	public static void main(String[] args) {
    		Person2 person2 = new Student2();
    		person2 = new Teacher2();
    		test(person2);
    	}
    	
    	public static void test(Person2 person2) {//person2 = new Teacher2()
    //		//当用Student2类型的引用指向Teacher2类型的对象时,因为Student2和Teacher2没有关系.所以会报ClassCastException(类型转换异常)
    //		Student2 student2 = (Student2)person2;
    //		student2.run();
    		
    		//容错处理
    		//如果person2对应的对象不是Student2或者Student2的子类的对象,这里返回false
    		if (person2 instanceof Student2) {
    			Student2 student2 = (Student2)person2;
    			student2.run();
    		}else {
    			System.out.println("类型转换错误");
    		}
    		
    		//instanceof的前后必须有继承关系
    //		Dog1 dog1 = new Dog1();
    //		if (dog1 instanceof Student2) {
    //			
    //		}
    	}
    }
    
    class Person2{
    	String name;
    	int age;
    	
    	public void show() {
    		System.out.println("show");
    	}
    }
    
    class Student2 extends Person2{
    	public void run() {
    		System.out.println("run");
    	}
    }
    
    class Teacher2 extends Person2{
    	public void eat() {
    		System.out.println("eat");
    	}
    }
    
    class Dog1{
    	
    }
    

Object类及常用三种方法

是所有类的父类

三个常用的方法:

  1. 取得对象信息的方法:toString()

    该方法在打印对象时被调用,将对象信息变为字符串返回,默认输出对象地址。

    可以通过重写Object类的toString()方法来输出对象属性信息

    class Student
    {
        String name = "Mary";
        int age = 21;
        public String toString()
        {
            return "姓名:"+name+",年龄:"+age;
        }
    }
    
  2. 对象相等判断方法:equals()

    该方法用于比较对象是否相等,而且此方法必须被重写。equals()方法比较的是两个对象的地址,所以必须重写方法才能到达目的。

  3. 对象签名:hashCode()

    该方法用来返回其所在对象的物理地址(哈希码值),常会和equals方法同时重写,确保相等的两个对象拥有相等的.hashCode。

  4. 对于clone方法的说明:
    		 * 1.要想使用clone方法完成克隆,当前类必须实现了Cloneable这个接口
    
    		 * 2.要想使用必须要重写这个方法
    
    		 * 3.不是所有系统类都实现了他.比如Object,Integer,String等.实现了他的有ArrayList,LinkedList
    
    		 * 4.clone没有调用new方法和构造方法.克隆不会调用构造方法,克隆时,根据源对象类型先分配和源对象
    
    		 * 相同的内存,然后将源对象中的各个域中数据拷贝过来,最后返回对象地址。
    
    		 * new时,第1步也是先分配内存,然后调用构造方法初始化数据,最后将对象地址返回,
    
    		 * 外界就可以通过这个对象地址(引用)操作此对象。
    
    		 * 5.调用clone没有办法实现完全的深拷贝.对于调用clone的对象是深拷贝,但是对于他的成员默认还是浅拷贝,
    
    		 * 如果想让成员也深拷贝,就要在重写的clone方法中调用成员的clone方法,依次类推.
    
    		 */
    

内部类

定义在一个类的内部的类,内部类的地位与外部类的成员变量,成员方法平等,内部类也可以看作是外部类的成员,成员之间可以相互调用。

public class Demo14 {
	public static void main(String[] args) {
		Outer outer = new Outer();
		outer.age = 10;
		//调用内部类成员的方式
		//两种
		//第一种:借助于外部类的方法实现
		outer.show();
		//第二种:直接在这里调用
    	//引用:外部类.内部类
    	//构成:外部类对象的引用.new 内部类的构造方法
		Outer.Inner inner = outer.new Inner();
		inner.eat();
	}
}

class Outer{
	int age;
	//内部类
	class Inner{
		int height;
		public void eat() {
			System.out.println("eat");
		}
	}
	public void show() {
		System.out.println("show");
		Inner inner = new Inner();
		inner.eat();
	}
}

class A1{
	
}

class B1{
	
}
//说明功能
//我们可以通过内部类让java间接实现多继承
class X extends A1{
	class Y extends B1{
		
	}
}

1.局部内部类

  1. 定义在一个类方法中的类

  2. 作用范围:从定义开始到当前的方法结束

  3. 当方法中同时存在局部内部类与成员变量时,成员变量的使用范围就会从原来的基础上进行扩大.

    • 原因:在当前的情况下,程序会默认让final去修饰height.所以当局部变量所在的方法结束的时候,变量没有被释放,保存的值还在.

    • 关于变量前面的final:

    • 前提:变量必须与局部内部类同时存在.并且在局部内部类中使用了当前的局部变量

    • 在jdk1.7之前要想保住局部变量的值,要手动添加final

    • 在jdk1.7之后,java的内部机制已经在变量的前面默认添加了final

  4. public class Demo15 {
    	public static void main(String[] args) {
    		Outer1 outer1 = new Outer1();
    		outer1.show();
    		Test11 test11 = new Test11();
    		test11.play();
    	}
    }
    
    class Outer1{
    	int age;
    
    	public void show() {
    		int height=8;
    		//局部内部类
    		class Inner{
    			
    			public void eat() {
    				System.out.println("eat"+height);
    			}
    		}
    		
    		System.out.println("show");
    		Inner inner = new Inner();
    		inner.eat();
    	}
    }
    
    class Test11{
    	public void play() {
    		//我们通过局部内部类实现了功能的私有化,并对方法内部的代码进行了整理,增强了代码的可读性和可操作性.
    		
    		//因为函数的定义不能嵌套,所以这里要通过局部内部类实现
    //		public void gongneng1(){
    //			System.out.println("功能1");
    //		}
    //		public void gongneng2(){
    //			System.out.println("功能2");
    //		}
    		
    		class Inner{
    			public void gongneng1(){
    			    System.out.println("功能1");
    			}
    			public void gongneng2(){
    				System.out.println("功能2");
    			}
    		}
    		
    		Inner inner = new Inner();
    		inner.gongneng1();
    		inner.gongneng2();
    	}
    	
    	public void run(){
    		//因为两个方法是play的局部内部类方法.play之外不可见
    //		gongneng1();
    //		gongneng2();
    	}
    
    }
    

2.静态内部类

静态内部类不一定有静态方法,有静态方法的一定是静态内部类

public class Demo17 {
	public static void main(String[] args) {
		//Out out = new Out();
		//Out.Inn inn = out.new Inn();
		//创建静态内部类对象
		//构成:  new  +  外部类名字.内部类的构造方法
		 Out.Inn inn =  new Out.Inn();
		 //调用方法
		 inn.play();
		 //调用静态方法
		// inn.show();
		 Out.Inn.show();
	}
}


class Out{
	static int age;
	//静态内部类不一定有静态方法,有静态方法的一定是静态内部类
	static class Inn{//静态内部类
		public void play() {
			System.out.println("play");
		}
		public static void show() {
			System.out.println("show");
		}
	}
}

3.匿名内部类

定义在一个类方法中的匿名子类对象,属于局部内部类。

创建匿名内部类对象注意点
  1. 匿名内部类对象必须有父类或者父接口。
匿名内部类对象的作用:
  1. 当只用到当前子类的一个实例对象的时候,定义好马上使用
  2. 当不好起名字的时候
  3. 可以更好的定义运行时的回调
匿名内部类注意事项(特点):

1、匿名内部类不能定义任何静态成员、方法。
2、匿名内部类中的方法不能是抽象的;
3、匿名内部类必须实现接口或抽象父类的所有抽象方法。
4、匿名内部类不能定义构造器;
5、匿名内部类访问的外部类成员变量或成员方法必须用static修饰;
6、内部类可以访问外部类私有变量和方法。

内部类的作用
  1. 间接实现了多继承

  2. 方便定义

  3. 只有外部类可以访问创建的内部类的属性和方法(包括私有方法)

  4. 同一个包中其他的类不可见,有了很好的封装性。

    public class Demo18 {
    	public static void main(String[] args) {
    		//研究匿名子类对象
    		Animal11 animal = new Animal11();
    		new Animal11().eat();//匿名对象
    		//匿名子类对象
    		//第一种方式:使用已有的子类创建匿名子类对象
    		//使用场景:已经创建好的子类可以多次使用,适用于相同的功能被多次调用
    		new Dog11().eat();
    		//第二种方式:这里也是Animal的匿名子类对象
    		//直接创建了没有名字的Animal的匿名子类对象
    		//构成: new +  父类的名字/接口的名字 + () + {写当前子类的成员} + ;
    		//使用场景:只能使用一次,使用完会被当做垃圾回收,适用于每次都使用不能的功能
    		new Animal11() {
    			@Override
    			public void eat() {
    				// TODO Auto-generated method stub
    				super.eat();
    			}
    			public void show() {
    				
    			}
    		}.show();
    		
    		//匿名内部类:
    		Test1 test1 = new Test1();
    		test1.canShuTest();
    		test1.canShuTest1();
    	}
    }
    //研究匿名子类对象
    class Animal11 {
    	public void eat() {
    		System.out.println("fu-eat");
    	}
    }
    class Dog11 extends Animal11
    {
    	public void eat() {
    		System.out.println("zi-eat");
    	}
    }
    
    //匿名内部类:
    class Test1{
    	public void show() {
    		//匿名内部类
    		new Animal() {
    			@Override
    			public void eat() {
    				// TODO Auto-generated method stub
    				super.eat();
    			}
    		};
    	}
    	//普通的匿名对象作为参数
    	public void canShuTest() {
    		System.out.println(new Animal());
    	}
    	//匿名内部类作为参数
    	public void canShuTest1() {
    		System.out.println(
    			new Animal() {
    				public void eat() {
    					// TODO Auto-generated method stub
    					super.eat();
    				}
    				@Override
    				public String toString() {
    					return "haha";
    				}
    			}
    		);
    	}
    	//普通的匿名对象作为返回值
    	public Animal fanHuiZhiTest() {
    		return new Animal();
    	}
    	//匿名内部类作为返回值
    	public Animal fanHuiZhiTest1() {
    		return new Animal() {
    			
    		};
    	}
    }
    
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值