第二部分-面向对象高级
一.static
1.用static修饰叫做静态变量,静态方法。
2.随着类的加载而加载,静态变量只会加载一次。static存放在堆中的一个静态区域。
3.通过 类.static 的方式去调用静态方法。
静态方法不可以调用非静态结构。根据产生时间来理解会简单很多。
4.static修饰的方法内根本没有this和super之说。那是针对对象的。
5.方法内操作的变量是静态变量时,建议为静态方法。
二.单例模式
1.在类的内部创建对象。
对比两种模式(特点、优缺点) 特点:
饿汉式:“立即加载”,随着类的加载,当前的唯一实例就创建了 懒汉式:"延迟加载",在需要使用的时候,进行创建。
优缺点:
饿汉式:(优点)写法简单,由于内存中较早加载,使用更方便、更快。是线程安全的。 (缺点)内存中占用时间较长。 懒汉式:(缺点)线程不安全 (放到多线程章节时解决)(优点)在需要的时候进行创建,节省内存空间。
public class BankTest { public static void main(String[] args) { // Bank bank1 = new Bank(); // Bank bank2 = new Bank(); Bank bank1 = Bank.getInstance(); Bank bank2 = Bank.getInstance(); System.out.println(bank1 == bank2); } } //饿汉式 class Bank{ //1. 类的构造器私有化 private Bank(){ } //2. 在类的内部创建当前类的实例 //4. 此属性也必须声明为static的 private static Bank instance = new Bank(); //3. 使用getXxx()方法获取当前类的实例,必须声明为static的 public static Bank getInstance(){ return instance; } }
三.代码块
1.用来格式{}
2.只能使用static进行修饰
3.具体使用:静态代码块与非静态代码块。
public class BlockTest { public static void main(String[] args) { System.out.println(Person.info);//先静态代码块,再静态属性 Person p1=new Person();//先非静态代码块,再构造器 System.out.println("------------"); Person p2=new Person();//创建一次实例就会执行一次非静态代码块 p1.eat(); p1.play(); } } class Person{ String name="李四"; int id=3445; public Person(){ System.out.println("构造器的测试。"); } public void eat(){ System.out.println("吃饭"); } public void play(){ System.out.println("玩乐"); } static String info ="信息"; { id=98; info="信息1"; System.out.println("非静态代码块测试"+id); } static{ System.out.println("静态代码块测试"); } //先静态代码块,再静态属性,再非静态代码块,最后是非静态的方法和属性 } RESULT: 静态代码块测试 信息 吃饭 非静态代码块测试98 构造器的测试。 ------------ 吃饭 非静态代码块测试98 构造器的测试。 吃饭 玩乐
先类后对象。先静态后实例。先父类后子类。先代码块后构造器。(非静态代码块也要早于构造器)
四.final
1.final可以修饰类,方法,属性。
2.final修饰类表示类不能被继承,修饰方法表示方法不能被重写。
final修饰变量则就变成了常量。
有点道理:员工要注重发展长处,保持竞争力。而管理层就要注意短板,减少犯错。一个是要冲,一个是要稳。不同阶段有不同重要的事。
3.final与static结合为全局常量。
五.抽象类
1.抽象类不能实例化,即不能创建对象。但存在构造器。
2.抽象类可以没有抽象方法。抽象方法的功能是确定的,但没有方法体。
3.抽象修饰方法和类
public class AbstractTest { public static void main(String[] args) { Student8 s8=new Student8(); // Person8 p8 =new Person8();不能实例化对象。 } } abstract class Person8{ public abstract void play(); public abstract void eat();//抽象方法,没有方法体 } class Student8 extends Person8{ @Override public void eat() { System.out.println("学生会吃"); } @Override public void play() { System.out.println("学生会玩"); }//子类要将父类的抽象方法进行重写,不然就会被认定为含有父类的抽象方法而报错 }
大国博弈,倒霉的肯定是小国。是这样的,布局向来也是要拿小棋去打开局面。去博弈。”
谈谈理解;抽象类及抽象方法还是有存在必要的。抽象方法所在的类为抽象类。比如求几何图形面积,求法虽然不同,但都是求面积,所以可以让子类重写抽象方法实行具体步骤。
进一步发现抽象其实是和多态紧密结合的。因为抽象不能创建对象,所以要用子类去创建对象。
4.模板方法设计模式
当功能的一部分确定时,而一部分是不确定的。将不确定的部分暴露出去,让子类去实现。
六.接口
1.接口基本知识
1.就是一套规范。
2.定义接口的关键字:interface
3.声明属性时:必须使用public static final(可以省略)就是说将为全局常量。
声明方法时:jdk8之前声明抽象方法,修饰为public abstract。
4.接口与类的关系:实现,implement。class A extends SuperA implement B,C
5.一个类可以实现多个接口。
6.接口与接口关系:可以多继承。
7.接口的多态.格式为:”接口 变量=new 实现类“。
public class InterfaceTest { public static void main(String[] args) { System.out.println(Flyable.MAX_NUM); Flyable p1=new Plane();// 接口的多态.格式为:”接口 变量=new 实现类“。 //p1.attrack; p1.fly(); Plane p2=new Plane(); p2.attrack(); p2.fly(); } } interface Flyable{ public static final int MAX_NUM=9;//属性可以省略public static final int MIN_SPEED=3000; void fly(); } interface Attract{ void attrack(); } abstract class pullet implements Attract{ @Override public void attrack() { System.out.println("子弹具有攻击性"); } } class Plane implements Flyable,Attract{ @Override public void fly() { System.out.println("飞机会飞"); } @Override public void attrack() { System.out.println("具有攻击性"); } }
2.接口例题
package chapter9.exer2; /* 有点意思,思考还是有趣的,不至于无聊到睡着 */ public class USBTest { public static void main(String[] args) { computer c1=new computer(); //1 接口实现类的对象 Printer p1=new Printer(); c1.test99(p1); //2 接口实现类的匿名对象 c1.test99(new campus()); //3 接口匿名实现类的对象 // 本来USB是一个接口,不能创建对象,因为有抽象方法。但是它相当于给自己进行了重写 USB usb1=new USB() { @Override public void start() { } @Override public void finish() { } }; c1.test99(usb1); //4.接口匿名实现类的匿名对象 c1.test99(new USB() { @Override public void start() { } @Override public void finish() { } }); } } interface USB{ public static final int id =9; public abstract void start(); public abstract void finish(); } class computer{ public void test99(USB usb){ usb.start(); System.out.println("数据开始传输"); usb.finish(); System.out.println("数据传输完成"); } } class Printer implements USB{ @Override public void start() { System.out.println("打字机开始工作"); } @Override public void finish() { System.out.println("打字机结束工作"); } } class campus implements USB{ public void start(){ System.out.println("照相机开始工作"); } @Override public void finish() { System.out.println("照相机结束工作"); } }
关于instanceof:本质上是看左边是否是右边的实例。
instanceof是Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false。
像这样是接口也是可以的。
if(vehicles[i] instanceof IPower){ ((IPower) vehicles[i]).power(); }
3.接口在jdk8以后的新特性
1.接口中可以使用静态方法,但只能被接口来调用不能使用其实现类来调用。
2.接口中声明的默认方法可以被实现类使用,那如果实现类对默认方法进行了重写,自然使用的是重写过后的。
3.类可以实现多个接口,但如果接口定义了同名同参数的方法,则实现类会报错。接口冲突。
4.子类继承了父类并实现了接口,父类和接口声明了同名同参数的方法,则子类优先类中的方法。
5.如何在子类(或实现类)中调用父类或接口中被重写的方法。
super.method4(); //调用父类中的 method3();//调用自己类中的方法 CompareA.super.method3(); //调用接口CompareA中的默认方法 CompareB.super.method3(); //调用接口CompareB中的默认方法
七.内部类
---类的第五个内容
1.内部类的分类:成员内部类(又有静态与非静态之分)和局部内部类
成员内部类:直接声明在外部类的里面。 > 使用static修饰的:静态的成员内部类 > 不使用static修饰的:非静态的成员内部类
局部内部类:声明在方法内、构造器内、代码块内的内部类 > 匿名的局部内部类 > 非匿名的局部内部类
2.内部类这节要讲的知识:
成员内部类的理解 如何创建成员内部类的实例 如何在成员内部类中调用外部类的结构
局部内部类的基本使用
例题1
package chapter9.exer6; public class OuterClass { public static void main(String[] args) { Person.Dog dog=new Person.Dog(); dog.eat(); //因为是内部类,所以还是要明确外部 //创建了内部类的一个对象。因为是静态的,所以不需要创建person对象 Person p1=new Person(); Person.Cat cat=p1.new Cat(); //这个是非静态的,所以比上面的多一点,要先创建person对象。 cat.eat(); cat.show("黑鸟"); cat.show1(); } } class Person { public void eat(){ System.out.println("人吃饭"); } int age=34; String name="黄鹂"; class Cat{ String name="白鸟"; public void eat(){ System.out.println("鸟吃食物"); } public void show(String name){ System.out.println("age = "+age); System.out.println("name = "+this.name);//本类中的name System.out.println("name = "+name);//形参中的name System.out.println("name = "+Person.this.name);//外部类中的name } public void show1(){ Person.this.eat();//调外部类的方法 eat();//调自己的方法 } } static class Dog{ public void eat(){ System.out.println("狗吃"); } } }
例题2
package chapter9.exer6; public class OuterClassTest1 { public static void main(String[] args) { //SubObject subObject=new SubObject(); //subObject.test();//1 //new SubObject().test();//2 //4 接口匿名实现类的匿名对象 new Object() { public void test() { System.out.println("test0"); } }.test(); //传统写法。先创建对象,再调用方法 C c1 = new C(); c1.testc(); //相当于把自己当作子类,然后重写了一遍方法, new C() { public void testc() { System.out.println("test3"); } }.testc(); } } class SubObject extends Object{ public void test (){ System.out.println("test1"); } } class C{ public void testc(){ System.out.println("test2"); } }
八.枚举
1.类的对象是有限而且固定,推荐使用枚举。
2.自写枚举类
package chapter9.exer7; public class EnumTest { public static void main(String[] args) { System.out.println(Season.SPRING); } } class Season{ // private final String seasonName; private final String seasonDesc; //2.将构造器私有化,使其无法创建对象 private Season(String seasonName, String seasonDesc) { this.seasonName = seasonName; this.seasonDesc = seasonDesc; } //3.获取特征,不希望被更改 public String getSeasonName() { return seasonName; } public String getSeasonDesc() { return seasonDesc; } public static final Season SPRING=new Season("春天","如坐春风"); public static final Season summer=new Season("夏天","荷叶田田"); public static final Season automn=new Season("秋天","秋风怒号"); public static final Season winter=new Season("冬天","白雪皑皑"); @Override public String toString() { return "Season{" + "seasonName='" + seasonName + '\'' + ", seasonDesc='" + seasonDesc + '\'' + '}'; } }
3.枚举关键字默认父类是java.lang.Enum
4.String toString(): 默认返回的是常量名(对象名),可以继续手动重写该方法! (关注)static 枚举类型[] values():返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值,是一个静态方法 (关注)static 枚举类型 valueOf(String name):可以把一个字符串转为对应的枚举类对象。要求字符串必须是枚举类对象的“名字”。如不是,会有运行时异常:IllegalArgumentException。 String name():得到当前枚举常量的名称。建议优先使用toString()。 int ordinal():返回当前枚举常量的次序号,默认从0开始
5.情况1:枚举类实现接口,在枚举类中重写接口中的抽象方法。当通过不同的枚举类对象调用此方法时,执行的是同一个方法。
情况2:让枚举类的每一个对象重写接口中的抽象方法。当通过不同的枚举类对象调用此方法时,执行的是不同的实现的方法。
九.注解
1.几个基本注解
@override 修饰方法,表示方法要进行重写。
@SuppressWarnings("unused") int num =29;表示未使用
@Deprecated : 表示修饰的方法或类已经过时。
2.自定义注解
3.元注解:用来修饰注解的注解
@Target 用来描述注解的适用范围。
@Retention 用于描述注解的生命周期。
3.J-unit单元测试
要求:所在的类必须是public,非抽象的,包含唯一空参的构造器。
所在的方法必须是public,非抽象的,非静态的,void无返回值,()参数的。
十.包装类
问题引入:基本数据类型的优势在于效率高,然而有很多场景无法使用基本数据类型。比如equals(object obj)形参很多时候只能使用引用数据类型。所以引入了包装类。
1.基本数据类型定义了相应的包装类:int-->Integer char -->Character.其余首字母大写即可。
2.int num=10;Integer obj=new Integer(10);
3.将基本数据类型转化为包装类
int i1=10; Integer i12=new Integer(i1);//方式1 System.out.println(i12); Integer integer = Integer.valueOf(i1);//方式2,推荐使用 System.out.println(integer);
4.将包装类转化为基本数据类型
Integer integer1 = Integer.valueOf(23); int i9=integer1.intValue();//转回去了 System.out.println(i9+4);结果为27
5.初始化值不一样,因为数据类型不一样
public void test3(){ System.out.println(new Account().integer);//表示null System.out.println(new Account().i);//表示0 }
class Account{ int i; Integer integer; }
6.自动拆箱与自动装箱
public void test4(){ int i1 =34; Integer integer=i1;//自动装箱 System.out.println(integer.toString()); int i2=integer;//自动拆箱 System.out.println(i2+4); }
7.string类型与基本数据类型之间的转换。
//基本数据类型到String类型方式一 int i=4; String str1=String.valueOf(i); System.out.println(str1); //方式二 int i1=5; String str2=i1+" "; System.out.println(str2); //Sting类型到基本数据类型 String str3="45"; int i4=4+Integer.parseInt(str3); System.out.println(i4);
Integer m=2; Integer n=2; System.out.println(m==n);//true, Integer x=128; Integer y=128; System.out.println(x==y);//false, //Integer和Byde在-128到127范围共用了一片空间,所以在这其中数值相等就是true, // 超过范围则要另外造对象,那么地址自然就不一样了。
十一.idea中的一些快捷键
ctrl +o:重写父类方法
ctrl +i :重写接口方法
CTRL+alt+left/right:返回上一次访问或下一次访问
ctrl +f :查找指定结构
ctrl+r :查找与替换
ctrl+shift+f:全项目搜索文本
ctrl +alt+l : 格式化代码
ctrl+/ :单行注释
ctrl+shift+/:多行注释
第1组:通用型
复制代码-copy ctrl + c 粘贴-paste ctrl + v 剪切-cut ctrl + x 撤销-undo ctrl + z 反撤销-redo ctrl + shift + z 保存-save all ctrl + s 全选-select all ctrl + a
第2组:提高编写速度(上)
智能提示-edit alt + enter 提示代码模板-insert live template ctrl+j 使用xx块环绕-surround with ... ctrl+alt+t 调出生成getter/setter/构造器等结构-generate ... alt+insert 自动生成返回值变量-introduce variable ... ctrl+alt+v 复制指定行的代码-duplicate line or selection ctrl+d 删除指定行的代码-delete line ctrl+y 切换到下一行代码空位-start new line shift + enter 切换到上一行代码空位-start new line before current ctrl +alt+ enter 向上移动代码-move statement up ctrl+shift+↑ 向下移动代码-move statement down ctrl+shift+↓ 向上移动一行-move line up alt+shift+↑ 向下移动一行-move line down alt+shift+↓ 方法的形参列表提醒-parameter info ctrl+p
第3组:提高编写速度(下)
批量修改指定的变量名、方法名、类名等-rename shift+f6 抽取代码重构方法-extract method ... ctrl+alt+m 重写父类的方法-override methods ... ctrl+o 实现接口的方法-implements methods ... ctrl+i 选中的结构的大小写的切换-toggle case ctrl+shift+u 批量导包-optimize imports ctrl+alt+o
第4组:类结构、查找和查看源码
如何查看源码-go to class... ctrl + 选中指定的结构 或 ctrl+n 显示当前类结构,支持搜索指定的方法、属性等-file structure ctrl+f12 退回到前一个编辑的页面-back ctrl+alt+← 进入到下一个编辑的页面-forward ctrl+alt+→ 打开的类文件之间切换-select previous/next tab alt+←/→ 光标选中指定的类,查看继承树结构-Type Hierarchy ctrl+h 查看方法文档-quick documentation ctrl+q 类的UML关系图-show uml popup ctrl+alt+u 定位某行-go to line/column ctrl+g 回溯变量或方法的来源-go to implementation(s) ctrl+alt+b 折叠方法实现-collapse all ctrl+shift+ - 展开方法实现-expand all ctrl+shift+ +
第5组:查找、替换与关闭
查找指定的结构 ctrl+f 查找与替换-replace ctrl+r 直接定位到当前行的首位-move caret to line start home 直接定位到当前行的末位 -move caret to line end end 全项目搜索文本-find in path ... ctrl+shift+f
第6组:调整格式
格式化代码-reformat code ctrl+alt+l 使用单行注释-comment with line comment ctrl + / 使用/取消多行注释-comment with block comment ctrl + shift + / 选中数行,整体往后移动-tab tab 选中数行,整体往前移动-prev tab shift + tab
关于调试:
1.普通断点:
2.方法断点:
3.属性断点:属性值发生改变的地方停留
4.条件断点:对于循环等等可以用这个
5.强制结束:发现了问题想要退出,不想再执行