final关键字
- 被final修饰的内容是无法再被改变的。
- final修饰的类不能有子类,即不能被继承
- 修饰成员变量时,变量是一个终值,不能再被改变,定义时需要赋初始值。
- 修饰局部变量时,也是一个终值,不能再被改变。
- final修饰的方法不允许被重写。
abstract关键字
- 抽象方法,抽象类
- 声明:不写函数体的函数,可以叫声明。
- 在继承中,提取父类方法时,每个子类都要实现该抽象方法,有函数体。父类不能决定子类中的实现方法。父类中只要写声明就好。(负责制定一个规则,内容自己去实现)
- 抽象方法:将方法的实现交给子类,只有方法声明的方法叫抽象方法,拥有抽象方法的类叫抽象类。
- 抽象类不一定有抽象方法,有抽象方法的一定是抽象类。
- 继承了抽象类的子类一定要实现抽象方法,若不实现就将自己也声明成抽象的。
- 抽象类不能实例化(不能直接创建对象),必须要通过子类实现,即抽象类一定有子类
比较final,abstract,static,private
不能与abstract同时存在的关键字:
- final:被final修饰的类不能有子类,方法不能重写,abstract修饰的类必须有子类,且方法必须被重写。
- static:static修饰的方法可以直接被类名调用,abstract必须通过子类实现,static修饰的方法跟随着字节码文件的出现而出现,出现的时间早于对象创建的时间。
- private:修饰的方法不能重写,abstract修饰的方法必须被重写。
- 抽象类中可以没有抽象方法,但是有抽象方法的类必须要被abstract修饰,即必为抽象类。
- 抽象方法没有方法体,只是抽象声明。
接口:interface
- 一般接口中不写成员变量,只写方法–只写规则,又将接口称为方法列表
- 让实现它的类去实现方法列表中的全部方法。
- 使用implements。
- 父类与接口的功能如何分配:一般父类中放的是主要功能,接口中放的是额外的功能,接口作为父类的补充.
- 接口不能创建对象,接口和接口之间可以有继承关系,只能是多继承。
- 从jdk1.7开始,以后的接口中可以有方法的实现,但是方法必须使用static或default修饰
- 如果一个类实现两个接口,这两个接口同时有相同的抽象方法,在类中只需要重写一次这个方法。
如果接口中有default修饰的方法不需要重写。
如果两个接口里的方法名相同都是default方法,里面的方法体不同,在类中需要重写该方法。
如果两个接口中方法名,参数都相同的方法,一个接口是抽象方法,另一个是default修饰有方法体。这时该类也必须重写该方法。
接口(interface)和abstract类的区别
1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
4.抽象类中的抽象方法的访问类型可以是public,protected和(默认类型,虽然eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
5. 抽象类中可以包含静态方法,接口中不能包含静态方法
6. 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。
7. 一个类可以实现多个接口,但只能继承一个抽象类。
设计模式
- 前人总结出来的对一些常见问题的解决方案,后人直接拿来用即可。
- 常用的设计模式:单例,工厂,代理,适配器,装饰,模板,观察者等,一共23种
单例设计模式
-
只允许有一个对象,需要建立一个单例类来描述
-
全局的访问点,通过static来实现,
-
作用:传值,作为全局的访问点
-
好处:可以让两个对象在完全没有关系的前提下,实现值的传递,降低了耦合性,提高了内聚性
-
如何做到低耦合高内聚:在处理类与类关系的时候,让类之间的关系越紧密耦合性越高,内聚性越低.反之,关系越松散耦合性越低,内聚性越高.
-
在单例中,一般只有向外提供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类
-
每个Java应用程序都有一个Runtime类实例,使应用程序能够与其运行的环境相连接。
-
可以通过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.);//可用的最大内存量
多态
-
多态:一种事物的多种形态. :狗 == 动物 == 生物 花 == 植物 == 生物 人== 高等动物 == 动物
-
继承是多态的前提
-
当父类与子类有同名属性或方法时
- 成员变量:编译的时候能不能访问看父类,运行的时候也看父类
- 成员方法:编译的时候能不能访问看父类,运行的时候看子类
- 静态成员方法:编译运行都看父类
-
程序运行分成三个阶段:预编译,编译,运行
-
预编译:程序打开的时候,活儿已经干完了.(预处理命令 #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("猪吃"); } }
-
-
转型:
-
向上转型:相当于是自动类型转换,多态本身就是向上转型。
Person1 person1 = new Student1();
-
向下转型:相当于强制类型转换
-
作用:解决多态中无法调用子类特有属性的缺点
-
Student1 student121 = new Person1(); 1.这是不是父类的引用指向子类的对象,不是向上转型.使用子类的引用指向父类的对象是错误的. 2.这里不是多态,所以不是向下转型
instanceof
-
这是一个运算符
-
构成:对象 instanceof 类或者类的子类
-
原理说明:确定当前的对象是否是后面的类或者子类的对象,是返回true,不是false
-
作用:进行容错处理,增加用户体验
-
instanceof的前后必须有继承关系
-
代码实例
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类及常用三种方法
是所有类的父类
三个常用的方法:
-
取得对象信息的方法:toString()
该方法在打印对象时被调用,将对象信息变为字符串返回,默认输出对象地址。
可以通过重写Object类的toString()方法来输出对象属性信息
class Student { String name = "Mary"; int age = 21; public String toString() { return "姓名:"+name+",年龄:"+age; } }
-
对象相等判断方法:equals()
该方法用于比较对象是否相等,而且此方法必须被重写。equals()方法比较的是两个对象的地址,所以必须重写方法才能到达目的。
-
对象签名:hashCode()
该方法用来返回其所在对象的物理地址(哈希码值),常会和equals方法同时重写,确保相等的两个对象拥有相等的.hashCode。
-
对于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.局部内部类
-
定义在一个类方法中的类
-
作用范围:从定义开始到当前的方法结束
-
当方法中同时存在局部内部类与成员变量时,成员变量的使用范围就会从原来的基础上进行扩大.
-
原因:在当前的情况下,程序会默认让final去修饰height.所以当局部变量所在的方法结束的时候,变量没有被释放,保存的值还在.
-
关于变量前面的final:
-
前提:变量必须与局部内部类同时存在.并且在局部内部类中使用了当前的局部变量
-
在jdk1.7之前要想保住局部变量的值,要手动添加final
-
在jdk1.7之后,java的内部机制已经在变量的前面默认添加了final
-
-
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、匿名内部类不能定义任何静态成员、方法。
2、匿名内部类中的方法不能是抽象的;
3、匿名内部类必须实现接口或抽象父类的所有抽象方法。
4、匿名内部类不能定义构造器;
5、匿名内部类访问的外部类成员变量或成员方法必须用static修饰;
6、内部类可以访问外部类私有变量和方法。
内部类的作用
-
间接实现了多继承
-
方便定义
-
只有外部类可以访问创建的内部类的属性和方法(包括私有方法)
-
同一个包中其他的类不可见,有了很好的封装性。
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() { }; } }