/*接口类*/
public interface MsgListener{
public void afterMsgRecived(String msgData);
}
/*工具类*/
public class Tools{
public static void getMsgData(String reciver,MsgListener listener){
reciver+=reciver;
//关键的来了
listener.afterMsgRecived(reciver);
}
}
/*调用类*/
public static void main(String[] args){
String reciver="JACK THE REAPER";
//调用
Tools.getMsgData(reciver,new MsgListener(){
@override
public void afterMsgRecived(String msgData){
System.out.println(msgData);
}
});
}
你会看到控制台输出:“JACK THE REAPERJACK THE REAPER”;
ArrayList 数据结构是数组 查找效率更高
LinkedList 数据结构是双向链表 增加删除效率高
LinkedList 更占用内存
equals相等两个对象,则hashcode一定要相等。但是hashcode相等的两个对象不一定equals相等。
单例模式
饿汉式
好处是没有线程安全的问题,坏处是浪费内存空间。
public class Singletion {
private static Singletion instance = new Singletion();//饿汉式 在初始化时就先创建好对象 ,获取对象的时候直接返回
public Singletion(){
}
public static Singletion getInstance(){
return instance;
}
}
懒汉式
有线程安全和线程不安全两种写法,区别就是synchronized关键字。
线程不安全
public class Singletion {
private static Singletion instance;
public Singletion (){
}
public static Singletion getInstance(){
if(instance == null){
instance = new Singletion();//用的时候才去检查有没有实例,如果有则返回,没有则新建。
}
return instance;
}
}
线程安全
public class Singletion {
private static Singletion instance;
public Singletion (){
}
public static synchronized Singletion getInstance(){
if(instance == null){
instance = new Singletion();//用的时候才去检查有没有实例,如果有则返回,没有则新建。
}
return instance;
}
}
双重检查
public class Singletion {
private volatile static Singletion instance;
public Singletion (){
}
public static Singletion getInstance(){
if(instance == null){
synchronized(Singletion.class){
if (instance == null){
instance = new Singletion();
}
}
}
return instance;
}
}
静态类
public class Singletion {
private static class SingletionHolder {
private static final Singletion INSTANCE = new Singleton();
}
private Singletion (){}
public static final Singletion getInstance() {
return SingletionHolder.INSTANCE;
}
}
工厂模式
步骤1:创建一个接口
public interface Shape {
void draw();
}
步骤 2:创建实现接口的实体类。
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("画一个矩形");
}
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("画一个圆");
}
}
步骤 3 创建一个工厂,生成基于给定信息的实体类的对象。
public class ShapeFactory {
//使用 getShape 方法获取形状类型的对象
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Rectangle();
}
return null;
}
}
步骤 4 使用该工厂,通过传递类型信息来获取实体类的对象。
public class FactoryPatternDemo {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory();
//获取 RECTANGLE 的对象,并调用它的 draw 方法
Shape shape1 = shapeFactory.getShape("RECTANGLE");
//调用 RECTANGLE 的 draw 方法
shape1.draw();
//获取 CIRCLE 的对象,并调用它的 draw 方法
Shape shape2 = shapeFactory.getShape("CIRCLE");
//调用 Rectangle 的 draw 方法
shape2.draw();
}
}
输出结果
画一个矩形
画一个圆
观察者模式
实现
观察者模式使用三个类 Subject、Observer 和 Client。Subject 对象带有绑定观察者到 Client 对象和从 Client 对象解绑观察者的方法。我们创建 Subject 类、Observer 抽象类和扩展了抽象类 Observer 的实体类。
步骤 1 创建 Subject 类
import java.util.ArrayList;
import java.util.List;
public class Subject {
private List<Observer> observers
= new ArrayList<Observer>();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyAllObservers();
}
public void attach(Observer observer){
observers.add(observer);
}
public void notifyAllObservers(){
for (Observer observer : observers) {
observer.update();
}
}
}
步骤 2 创建 Observer 类。
public abstract class Observer {
protected Subject subject;
public abstract void update();
}
步骤 3 创建实体观察者类。
public class BinaryObserver extends Observer{
public BinaryObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "int类型的变量转换为二进制表示的字符串-->"
+ Integer.toBinaryString( subject.getState() ) );
}
}
public class HexaObserver extends Observer{
public HexaObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "int类型的变量转换为十六进制表示的字符串-->" + Integer.toHexString( subject.getState() ).toUpperCase() );
}
}
步骤 4 使用 Subject 和实体观察者对象。
public class ObserverPatternDemo {
public static void main(String[] args) {
Subject subject = new Subject();
new BinaryObserver(subject);
new HexaObserver(subject);
System.out.println("第一次改变-->15");
subject.setState(15);
System.out.println("第二次改变--> 10");
subject.setState(10);
}
}
输出
第一次改变-->15
int类型的变量转换为二进制表示的字符串-->1111
int类型的变量转换为十六进制表示的字符串-->F
第二次改变-->10
int类型的变量转换为二进制表示的字符串-->1010
int类型的变量转换为十六进制表示的字符串-->A
如果两个对象equals, 他们的hashcode一定相等。
如果两个对象不equals,他们的hashcode有可能相等。
如果两个对象hashcode相等,他们不一定equals。
如果两个对象hashcode不相等,他们一定不equals。
答:Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加0.5然后进行下取整。
class A {
static {
System.out.print("1");
}
public A() {
System.out.print("2");
}
}
class B extends A{
static {
System.out.print("a");
}
public B() {
System.out.print("b");
}
}
public class Hello {
public static void main(String[] args) {
A ab = new B();
ab = new B();
}
}
答:执行结果:1a2b2b。创建对象时构造器的调用顺序是:先初始化静态成员,然后调用父类构造器,再初始化非静态成员,最后调用自身构造器。
显示转换就是类型强转,把一个大类型的数据强制赋值给小类型的数据;隐式转换就是大范围的变量能够接受小范围的数据;隐式转换和显式转换其实就是自动类型转换和强制类型转换。
接口中声明全是public static final修饰的常量
接口中所有方法都是抽象方法
接口是没有构造方法的
接口也不能直接实例化
接口可以多继承
抽象类有构造方法,接口没有构造方法
抽象类只能单继承,接口可以多继承
包含抽象方法的类,一定是抽象类。
抽象类可以有普通方法,接口中的所有方法都是抽象方法
接口的属性都是public static final修饰的,而抽象的不是
不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,
List:线性表、Set:无序集合。
顺序存储、可以有重复值。
无序存储、不能有重复值。
以键值对存储数据
元素存储循序是无须的
不允许出现重复键
Java 的异常处理模型基于三种操作 :
finally关键字
throw、throws关键字
throw关键字:语句抛出异常
语法:throw (异常对象);
throws关键字:声明异常(方法抛出一个异常)
语法:
(修饰符)(返回值类型)(方法名)([参数列表])[throws(异常类)]{…}
public void doA(int a) throws Exception1,Exception3{…}
UserStruct.ByReference idBuffer =new UserStruct().ByReference();
ByReference 不是静态类,因此不能使用“外部类.内部类”的形式。
解决方案1:将ByReference更改为静态类
解决方案2:UserStruct.ByReference idBuffer =new UserStruct().new ByReference();
Java高级特性——反射
反射机制的相关类
类名 | 用途 |
---|---|
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量(成员变量也称为类的属性) |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
获取class文件对象的几种方法
/*方式一
使用类的对象获取
每个类都使用Object作为父类,Object类方法 getClass()
返回这个类的class文件对象,方法返回值Class类型对象
*/
Person person = new Person();
Class<? extends Person> objectPerson = person.getClass();
/*方式二
使用类的静态属性获取
类名.class 返回这个类的class文件对象.属性运行结果也是Class类型对象
*/
try {
Class<?> objectPerson = Class.forName("Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
/*方式三
使用Class类的静态方法获取
Class类静态方法 forName(String 类名) 传递字符串类名
获取到这个类的class文件对象,方法返回值也是Class类型对象
*/
Class<? extends Person> objectPerson = Person.class;
java注解-最通俗易懂的讲解
@Retention 注解指定了被修饰的注解的生命周期
@Target 指定了注解运用的地方。
注解的属性
注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
int id();
String msg();
}
上面代码定义了 TestAnnotation 这个注解中拥有 id 和 msg 两个属性。在使用的时候,我们应该给它们进行赋值。
赋值的方式是在注解的括号内以 value=”” 形式,多个属性之前用 ,隔开。
@TestAnnotation(id=3,msg="hello annotation")
public class Test {
}
注解中属性可以有默认值,默认值需要用 default 关键值指定。比如:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
public int id() default -1;
public String msg() default "Hi";
}
因为有默认值,所以无需要再在 @TestAnnotation 后面的括号里面进行赋值了。
@TestAnnotation()
public class Test {}
栈区、堆区、静态区/方法区
1、栈区:由编译知器自动分配释放,存放函数的参数值、局部变量的值等、基本类型的变量,例如int a=3中的a、对象的引用变量,例如Thread t=new Thread()中的t、具体方法执行结束之后,系统自动释放JVM内存资源。
2、堆区:一般由程序员分配释放,存放由new创建的对象和数组,jvm不定时道查看这个对象,如果没有引用指向这个对象就内回收。
3、静态区/方法区:存放全局变量,静态变量和字符串常量,不释放和整个应用的生命周期一样。