首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

Java入门系列-27-反射

咱们可能都用过 Spring AOP ,底层的实现原理是怎样的呢? 反射常用于编写工具,企业级开发要用到的 Mybatis、Spring 等框架,底层的实现都用到了反射。能用好反射,就能提高我们编码的核心能力。 反射机制 JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性。 作用: 在运行时判断任意一个对象所属的类 在运行时构造任意一个类的对象 在运行时判断任意一个类所具有的成员变量和方法 在运行时调用任意一个对象的成员变量和方法 生成动态代理 常用的类: java.lang.Class:代表一个类 java.lang.reflect.Method:代表类的方法 java.lang.reflect.Field:代表类的成员变量 java.lang.reflect.Constructor:代表类的构造方法 Class 类 Class 类的实例表示正在运行的 Java 应用程序中的类和接口,Class 没有公共构造方法,Class 对象是在加载类时由 Java 虚拟机及通过调用类加载器中的 defineClass 方法自动构造的。 一个类在 JVM 中只会有一个 Class 实例 一个 Class 对象对应的是一个加载到 JVM 中的一个 .class 文件 每个类的实例都会记得自己是由哪个 Class 实例所生成 通过 Class 可以完整地得到一个类中的完整结构 获取 Class 对象 获取 Class 对象有4种方式,前三种比较常用。 首先创建一个类用于测试 package com.jikedaquan.reflection; public class User { private int id; private String username; private String password; public User() { } public User(int id, String username, String password) { super(); this.id = id; this.username = username; this.password = password; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public void show() { System.out.println("Hello"); } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", password=" + password + "]"; } } 编写测试 package com.jikedaquan.reflection; public class GetClass { public static void main(String[] args) { //方法1 try { Class clz1=Class.forName("com.jikedaquan.reflection.User"); } catch (ClassNotFoundException e) { e.printStackTrace(); System.out.println("找不到指定类"); } //方法2 Class clz2=User.class; //方法3 User user=new User(); Class clz3=user.getClass(); //方法4 类的加载器 try { Class clz4=GetClass.class.getClassLoader().loadClass("com.jikedaquan.reflection.User"); } catch (ClassNotFoundException e) { e.printStackTrace(); System.out.println("找不到指定类"); } } } 方法1语法:Class Class对象 = Class.forName(包名+类名); 方法2语法:Class Class对象 = 类名.class; 方法3语法:Class Class对象 = 对象.getClass(); getClass() 方法是从 Object 类中继承过来的 获取类的结构 Class 类常用方法 方法名称 说明 Annotation[] getAnnotations() 返回此元素上存在的所有注解 Constructor getConstructor(Class<?>... parameterTypes) 获取指定参数的构造函数 Constructor<?>[] getConstructors() 返回包含的公有构造方法 Constructor<?>[] getDeclaredConstructors() 返回所有构造方法 Field getDeclaredField(String name) 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段 Method getDeclaredMethod(String name, Class<?>... parameterTypes) 根据方法名和参数获取方法对象 API 中可以看到有两种获取结构的方式:getDeclaredXxx()和getXxx();getDeclaredXxx()可以获取所有包括私有的 获取类的结构 package com.jikedaquan.reflection; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class GetClassStruct { public static void main(String[] args) { try { Class clz=Class.forName("com.jikedaquan.reflection.User"); System.out.println("===========构造==========="); //获取构造方法 Constructor[] cons=clz.getDeclaredConstructors(); for (Constructor constructor : cons) { System.out.println(constructor); } //获取字段 System.out.println("===========字段==========="); Field[] fields=clz.getDeclaredFields(); for (Field field : fields) { System.out.println(field); } //获取方法 System.out.println("===========方法==========="); Method[] methods=clz.getDeclaredMethods(); for (Method method : methods) { System.out.println(method); } //获取父类 System.out.println("===========父类==========="); Class supperClass=clz.getSuperclass(); System.out.println(supperClass.getName()); //获取实现的接口 System.out.println("===========接口==========="); Class[] interfaces=clz.getInterfaces(); for (Class interf : interfaces) { System.out.println(interf); } //获取注解 System.out.println("===========注解==========="); Annotation[] annotations=clz.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } } 调用类的指定方法、属性 获取构造方法并实例化对象 注意:jdk1.9弃用此方式实例化对象Object obj=clz.newInstance(); 通过反射获取有参或无参构造后方可实例化化对象 package com.jikedaquan.reflection; import java.lang.reflect.Constructor; public class CallConstructor { public static void main(String[] args) { //获取User 的 Class Class<User> clz=User.class; //获取无参构造方法并实例化 try { //getConstructor()方法不传参即无参 Constructor<User> constructor=clz.getConstructor(); User user=constructor.newInstance(); System.out.println(user); } catch (Exception e) { e.printStackTrace(); } //获取有参构造方法并实例化 try { Constructor<User> constructor=clz.getConstructor(int.class,String.class,String.class); User user=constructor.newInstance(18,"张三","abc123"); System.out.println(user); } catch (Exception e) { e.printStackTrace(); } } } 获取指定构造方法时,第二个参数为动态参数,不填写即获取无参构造方法,填写指定个数和指定类型.class可获取对应方式的构造方法。 调用类中的方法 package com.jikedaquan.reflection; import java.lang.reflect.Method; public class CallMethod { public static void main(String[] args) { //获取User 的 Class Class<User> clz=User.class; //获取无参方法 show try { Method method=clz.getMethod("show"); //执行clz中的方法 method.invoke(clz.getConstructor().newInstance()); } catch (Exception e) { e.printStackTrace(); } //获取一个参数为String的方法 try { Method method=clz.getMethod("setUsername", String.class); //反射实例化对象 User user=clz.getConstructor().newInstance(); //执行这个对象的方法 method.invoke(user, "反射"); //测试结果 System.out.println(user); } catch (Exception e) { e.printStackTrace(); } } } 如果有多个参数,获取方法:getMethod("方法名称",参数1.class,参数2.class,参数3.class) 多个参数执行时:method.invoke(对象,参数1,参数2,参数3); 动态代理 动态代理是指客户通过代理类来调用其他对象的方法,并且是在程序运行时根据需要创建目标类的代理对象。 原理: 使用一个代理将对象包装起来,然后用该代理对象取代原对象,任何对原始对象的调用都要通过dialing,代理对象决定是否以及何时将方法调用转到原始对象上。 生活中海外代购其实就用到了代理,你可能不方便出国,但是代购可以,最终帮你完成购买行为。 以代购为例子完成静态代理 package com.jikedaquan.reflection; //购买接口(约定) interface Buy{ void buyProduct(); } //被代理的 class Customer implements Buy{ @Override public void buyProduct() { System.out.println("购买商品"); } } //代理 class ProxyBuy implements Buy{ private Customer customer; public ProxyBuy(Customer customer) { this.customer=customer; } @Override public void buyProduct() { System.out.println("代理:出国"); //被代理的对象的行为 customer.buyProduct(); System.out.println("代理:回国"); } } public class TestStaticProxy { public static void main(String[] args) { Customer customer=new Customer(); ProxyBuy proxyBuy=new ProxyBuy(customer); proxyBuy.buyProduct(); } } 那么动态代理意味着不能只代理 Customer 类的行为,还可以代理其他类的行为 package com.jikedaquan.reflection; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //工厂接口 interface Factory{ void product(); } //电脑工厂 class ComputerFactory implements Factory{ @Override public void product() { System.out.println("生产电脑"); } } //动态代理处理器 class MyInvocationHandler implements InvocationHandler{ //要被代理的对象 private Object proxyObj; //产生代理对象 public Object bind(Object proxyObj) { this.proxyObj=proxyObj; return Proxy.newProxyInstance( proxyObj.getClass().getClassLoader(), proxyObj.getClass().getInterfaces(), this ); } //代理对象实际执行的方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理:收收费"); Object result=method.invoke(proxyObj, args); System.out.println("代理:代理完成"); return result; } } public class TestDynamicProxy { public static void main(String[] args) { //创建代理对象生产器 MyInvocationHandler invocationHandler=new MyInvocationHandler(); //创建要被代理的对象 ComputerFactory computerFactory=new ComputerFactory(); //生产代理对象 Object factoryProxy=invocationHandler.bind(computerFactory); Factory factory=(Factory) factoryProxy; factory.product(); //创建另一个要被代理的对象(上个示例静态代理的对象和接口) Customer customer=new Customer(); //生产代理对象 Object buyProxy=invocationHandler.bind(customer); Buy buy=(Buy) buyProxy; buy.buyProduct(); } } 在 main 方法中,创建了一个 MyInvocationHandler 对象,通过 bind 方法可以传入任意要被代理的对象,实现了动态。 重点来了,拿好小本子笔记!!!!! 实现动态代理的步骤: 1.创建要被代理的类的接口 2.创建要被代理的类实现类 3.创建代理对象处理器(MyInvocationHandler),实现 InvocationHandler 接口 4.编写生产代理对象的方法,方法内调用 Proxy.newInstance() 方法,返回代理对象 5.重写 InvocationHandler 的 invoke 方法 6.测试:创建代理对象生产器,生产代理对象

优秀的个人博客,低调大师

Java入门—输入输出流

File类的使用 文件是:文件可认为是相关记录或放在一起的数据的集合。 Java中,使用java.io.File类对文件进行操作 public class FileDemo { public static void main(String[] args) { String path = "E:\\pdd"; File f = new File(path); //判断是文件还是目录 System.out.println(f.isFile()); System.out.println(f.isDirectory()); } } image.png 对于File类还有其他很多方法的使用,建议在使用时进行查询文档。 字节流 字节输入流 :InputStream (读) 字节输出流 :OutputStream (写) image.png image.png FileInputStream 读取诸如图像数据的原始字节流,如图片,文件中的字节。 image.png image.png public class FileDemo { public static void main(String[] args) { String path = ""; // FileInputStream, try { FileInputStream fs = new FileInputStream(path); try { int n = fs.read(); System.out.print((char)n); fs.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } } } 代码中注意异常的继承关系,外层异常不能为内层异常的子类。 FileOutputStream 将数据写入文件中。 image.png image.png 缓冲流 BufferedInputStream BufferedOutputStream 缓冲流,当缓冲区满了,提交,减少频繁写入操作。 public class FileDemo { public static void main(String[] args) { String path = ""; try { FileOutputStream fos = new FileOutputStream(path); BufferedOutputStream bos = new BufferedOutputStream(fos); FileInputStream fis = new FileInputStream(path); BufferedInputStream bis = new BufferedInputStream(fis); bos.write(50); bos.write('a'); //提交数据到文件 bos.flush(); bos.close(); System.out.println(bis.read()); bis.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } 字符流 字符输入流 : Reader 字符输出流 : Writer 字节字符转换流 InputStreamReader 输入 OutputStreamWriter 输出 读写数据时保持编码一致。 对象的序列化和反序列化 对象序列化步骤: 创建一个类继承Serializable接口 创建对象 处理对象(写文件,发http,入库等) 读取对线 ObjectInputStream 对象输入流 ObjectOutputStream 对象输出流 示例: 新建一个Goods.java文件,定义一个Goods类并继承Serializable接口 public class Goods implements Serializable{ private String goodsId; private String goodsName; private double price; @Override public String toString() { return "Goods{" + "goodsId='" + goodsId + '\'' + ", goodsName='" + goodsName + '\'' + ", price=" + price + '}'; } public Goods(String goodsId, String goodsName, double price){ this.goodsId = goodsId; this.goodsName = goodsName; this.price = price; } public String getGoodsId() { return goodsId; } public void setGoodsId(String goodsId) { this.goodsId = goodsId; } public String getGoodsName() { return goodsName; } public void setGoodsName(String goodsName) { this.goodsName = goodsName; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } } 再建一个测试入口文件名为GoodsTest.java public class GoodsTest { public static void main(String[] args) { String path = "1.txt"; Goods gd = new Goods("001", "allen", 6.0); try { FileOutputStream fos = new FileOutputStream(path); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(gd); oos.writeBoolean(true); oos.flush(); oos.close(); System.out.println("-----------------------------------"); FileInputStream fis = new FileInputStream(path); ObjectInputStream ois = new ObjectInputStream(fis); try { Goods gt = (Goods)ois.readObject(); boolean b = ois.readBoolean(); System.out.println(gt); System.out.println(b); } catch (ClassNotFoundException e) { e.printStackTrace(); } ois.close(); }catch (IOException e){ e.printStackTrace(); } } } 对名为1.txt的文件进行类的存储和读取。 注:养成看官方文档的习惯,因为毕竟有些方法用的频率很少,当你使用时去查阅即可,文章中关于类的方法部分没有详情,请查阅官方手册,手册中写的很清楚。 如果文章对你有帮助记得点赞~,关注作者第一时间获得最新更新~~。 祝好~~~

优秀的个人博客,低调大师

Java入门系列-20-异常

为什么要进行异常处理 下面这段代码能否正常执行 public class DemoCalc { public static void main(String[] args) { int a=0; int b=0; int c=a/b; System.out.println("运算结果为:"+c); } } 结果是我们在控制台中看到一段错误提示,那是因为除数不能为0。异常就是在程序运行过程中发生的不正常事件,会中断运行的程序。 Java 使用了异常处理机制为程序提供了错误处理的能力,在程序中预先设置好对付异常的处理办法,待程序发生异常时对异常进行处理,处理完毕后,程序便可以继续运行。 下面来看一下Java中是如何进行异常处理的 如何进行异常处理 Java 的异常处理是通过5个关键字实现的:try、catch、finally、throw、throws 关键字 作用 try 执行可能产生异常的代码 catch 捕获异常 finally 无论是否发生异常,代码总能执行 throws 声明方法要抛出的异常 throw 手动抛出异常 常见异常及异常分类 Throwable 是Java 中所有错误和异常的父类 Error类:Throwable的子类,仅靠程序本身无法恢复的严重的错误。 Exception类:Throwable的子类,由Java应用程序抛出和处理的非严重错误 RuntimeException类:Exception的子类,运行时异常,不要求程序必须做出处理。 Checked异常:Exception的子类,程序必须处理该类异常。 常见异常类型 异常类型 说明 Exception 异常层次结构的父类 ArithmeticException 算数错误情形,如以零作除数 ArrayIndexOutOfBoundsException 数组下标越界 NullPointerException 尝试访问null对象成员 ClassNotFoundException 不能加载所需的类 IllegalArgumentException 方法接收到非法参数 ClassCastException 对象强制类型转换出错 NumberFormatException 数字格式转换异常,如把"abc"转换成数字 try-catch 语法: public void method(){ try{ //代码段1 //可能产生异常的代码段 //代码段2 }catch(异常类型 ex){ //对异常进行处理的代码段 } //代码段 } try-catch块捕获异常有三种情况: 1、try块中没有任何异常,try中正常,catch不会执行,正常执行try-catch后的代码。 2、try块中可能发生异常的代码段发生异常,代码段2不会执行,而是执行catch中异常处理的代码,正常执行try-catch后的代码。 catch中异常类型的printStackTrace() 方法能进行堆栈跟踪显示出程序运行到当前类的执行流程,异常堆栈信息中包含了异常的类型及异常出现的位置。 3、异常类型不匹配,程序将中断。比如try产生的异常为ArithmeticException,catch却用了 ClassCastException。 在控制台中接收数字做除法运算 import java.util.Scanner; public class DemoInput { public static void main(String[] args) { Scanner input=new Scanner(System.in); try{ System.out.println("请输入被除数(整数):"); int a=input.nextInt(); System.out.println("请输入除数(整数):"); int b=input.nextInt(); int c=a/b; System.out.println("结果:"+c); }catch(Exception ex) { ex.printStackTrace(); } System.out.println("程序结束"); } } try-catch-finally 语法: public void method(){ try{ //可能会发生异常的代码 }catch(异常类型 ex){ //异常处理 }finally{ //无论如何都要执行的代码 } } finally块:是否发生异常都执行 finllay块不执行的唯一情况:之前的代码中执行了 System.exit(1); 退出虚拟机 try-catch-finally的使用 import java.io.FileNotFoundException; import java.util.Scanner; public class DemoInput { public static void main(String[] args) { Scanner input=new Scanner(System.in); try{ System.out.println("请输入被除数(整数):"); int a=input.nextInt(); System.out.println("请输入除数(整数):"); int b=input.nextInt(); int c=a/b; System.out.println("结果:"+c); }catch(Exception ex) { ex.printStackTrace(); }finally { System.out.println("感谢您的使用"); } System.out.println("程序结束"); } } 如果在try块或catch块中有return语句,finally是否还会执行?运行下面代码断点调试观察结果。 public class TestReturn { public static void main(String[] args) { try { int a=1+1; System.out.println("try执行"); return; } catch (Exception e) { System.out.println("catch执行"); }finally { System.out.println("finally执行"); } } } try块或catch块中可以有return语句,如果有return语句会先执行finally最后再执行return。 多重catch try块中可能会发生多种异常,如果要不同的异常进行不同的处理,需要使用多重catch进行处理。 语法: public void method(){ try{ //可能发生异常的代码段 }catch(异常类型1 e){ //对异常类型1进行的处理的代码段 }catch(异常类型2 e){ //对异常类型2进行的处理的代码段 }catch(异常类型n e){ //对异常类型n进行的处理的代码段 } } 当try块中发生异常后,会逐个与catch中的异常类型进行匹配,匹配成功后,进入对应的catch进行异常处理,处理完成后不再进入其他catch,程序继续执行。 排列catch语句的顺序是:先子类后父类 发生异常时按顺序逐个匹配 只执行第一个与异常类型匹配的catch语句 将之前的代码 DemoInput.java 改造成多重catch import java.io.FileNotFoundException; import java.util.InputMismatchException; import java.util.Scanner; public class DemoInput { public static void main(String[] args) { Scanner input=new Scanner(System.in); try{ System.out.println("请输入被除数(整数):"); int a=input.nextInt(); System.out.println("请输入除数(整数):"); int b=input.nextInt(); int c=a/b; System.out.println("结果:"+c); }catch(InputMismatchException e) { System.out.println("输入的数有误!"); }catch(ArithmeticException e) { System.out.println("除数不能为0"); }catch(Exception ex) { System.out.println("发生未知异常"); }finally { System.out.println("感谢您的使用"); } System.out.println("程序结束"); } } 声明异常 throws 如果一个方法体内抛出了异常如何通知调用者,可以在方法上声明异常。 public class TestThrows { //声明异常,多个异常可以用逗号隔开 public void test()throws Exception,ClassNotFoundException{ //可能会发生异常的代码 } } 处理方式一:调用者处理异常 public static void main(String[] args) { TestThrows t=new TestThrows(); try { t.test(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } 处理方式二:调用者继续声明异常 public static void main(String[] args) throws ClassNotFoundException, Exception { TestThrows t=new TestThrows(); t.test(); } main方法继续声明异常,调用者就变成虚拟机了,发生异常则按默认方式处理,打印出来。 抛出异常 throw 除了系统自动抛出的异常外,有些问题需要程序员自行抛出异常 public class TestThrow { public void inputAge(int age) throws Exception { if (age<1) { throw new Exception("还有这种年龄?"); } } public static void main(String[] args) { TestThrow t=new TestThrow(); try { t.inputAge(-1); } catch (Exception e) { System.out.println("年龄有误:"+e.getMessage()); } } } 自行抛出异常后,还需要在方法上声明异常

优秀的个人博客,低调大师

Java入门之面向对象-多态

多态 多态是面向对象编程中最后一个(封装、继承、多态)也是最重要的特征。 程序设计当中,多态意味着,允许不同类的对象对同一消息做出不同的响应。 多态分为: 编译时多态 (设计时多态方法重载) 运行中多态 (程序运行时动态决定调用哪个方法) image.png 一般所说的java中的多态大多是运行时多态。 必要条件 满足继承关系 父类引用指向子类对象 示例 image.png 新建一个Animal类,作为动物基类,有两个属性,name、month,和一个eat方法。 Animal的子类中有自己特有的子类属性和方法, Cat中有weight、run(), Dog中有sex、sleep()。 且都重写了父类Animal中的eat()方法。 新建Animal.java: public class Animal { private String name; private int month; public Animal(){ } public Animal(String name, int month){ this.name = name; this.month = month; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getMonth() { return month; } public void setMonth(int month) { this.month = month; } public void eat(){ System.out.println("动物都有吃东西的能力"); } } 新建Cat.java: public class Cat extends Animal{ private double weight; public Cat(){ } public Cat(String name, int monnth, double weight){ super(name, monnth); this.weight = weight; } public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; } public void run(){ System.out.println("小猫快乐地奔跑"); } @Override public void eat() { super.eat(); System.out.println("猫吃鱼"); } } 新建Dog.java: public class Dog extends Animal { private String sex; public Dog(){ } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Dog(String name, int month, String sex){ this.setMonth(month); this.setName(name); this.setSex(sex); } public void sleep(){ System.out.println("小狗午睡"); } @Override public void eat() { System.out.println("狗吃肉"); } } 然后在定义一个测试文件Test.java: public class Test { public static void main(String[] args){ Animal one = new Animal(); Animal two = new Cat(); Animal three = new Dog(); one.eat(); two.eat(); three.eat(); } } 运行Test.java image.png 虽然都是吃这种行为,也同样都是Animal类型的引用,但是随着它具体在程序运行时实例化的对象类型不同,那么它的执行的具体行为能力是不一样的,这就是在java中多态的表现。 向上转型 父类引用指向子类实例:Animal one = new Animal(); 把一个子类对象转型为父类对象,向上转型(隐式转型、自动转型),代码中是父类引用指向子类实例, 父类引用指向子类实例,可以调用子类重写父类的方法以及父类派生的方法,无法调用子类独有的方法。 注意: 父类中的静态方法无法被子类重写,所以向上转型之后,只能调用父类原有的静态方法 向下转型(强制类型转换) 子类引用指向父类实例,必须进行强制类型转换,可以调用子类特有的方法。 必须满足转型条件才能强转。 instanceof运算符可以进行判断,左边对象是否是他右边对象的实例,换句话说就是左侧对象是否满足右侧对象类型的特征如果是,返回true。 if (obj instanceof Cat) 父类中的静态方法(含有static修饰的方法),只能被子类继承使用,无法被子类重写。 public static void say(){ } 抽象类 Java中使用抽象类,限制实例化 public abstract class A{ } 通过abstract 修饰的类叫做抽象类。 当一个类为抽象类时,就不允许实例化了,可以通过向上转型指向子类。 抽象类应用场景: 某个父类只是知道其子类应该包含怎样的方法,但无法准确知道这些子类如何实现这些方法。 当我们将父类设置为抽象类时,既可以借由父类和子类的继承关系限制子类随意性,同时也在一定程度上避免了无意义的实例化。 抽象方法 abstract 修饰的方法为抽象方法。 抽象方法要求: 不允许包含方法体 子类中必须重写父类中的抽象方法 如果不重写,子类自己必须被定义为抽象类 包含抽象方法的类必须是抽象类 总结: 抽象类不能直接实例化 子类如果没有重写父类所有的抽象方法,则也要定义为抽象类 抽象方法所在的类一定是抽象类 抽象类中可以没有抽象方法 static、final、private关键字不能与abstract 并存。 接口 当多个类型之间具有相同的行为能力的时候,java中可以借由接口来进行类型之间的联系。 通过接口可以解决java当中单继承所带来的一些类型无法共享的问题。 接口定义了某一批类所需要的遵守的规范 接口不关心这些类的内部数据,也不关心这些类里方法的实现细节,它只规定这些类里必须提供某些方法。 语法: [修饰符] interface 接口名 [extends 父接口1,父接口2...] { 零个到多个常量定义... 零个到多个抽象方法定义... 零个到多个默认方法定义...(jdk1.8新增) 零个到多个静态方法方法的定义...(jdk1.8新增) } 接口可以实现多继承,即一个子接口可以同时继承多个父接口 实现接口的类如果不能实现所有接口中待重写的方法,则必须设置为抽象类。 一个类可以继承自一个父类,同时实现多个接口 内部类 在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。与之对应,包含内部类的类称为外部类。 内部类分为四种: 成员内部类 静态内部类 方法内部类 匿名内部类 优势:内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包的其他类访问该类,更好的实现了信息隐藏。 1.成员内部类 内部类中最常见的就是成员内部类,也称为普通内部类。 如下: package com.imooc.people; //外部类 public class Demo { int name; public He getSex(){ return new He(); } //成员内部类 class He{ public String sex(){ return "男"; } } } 获取内部类对象实例的三种方式: public static void main(String[] args){ Demo a = new Demo(); a.name = 3; //方式一 Demo.He h = new Demo().new He(); //方式二 h = a.new He(); //方式三 a.getSex(); } 内部类在外部使用时,无法直接实例化,需要借由外部类信息才能完成实例化 内部类的访问修饰符,可以任意,但是访问范围会受到影响 内部类可以直接访问外部类的成员;如果出现同名属性,优先访问内部类中定义的 可以使用外部类.this.成员的方式,访问外部类中同名的信息 外部类访问内部类信息,需要通过内部类实例,无法直接访问 内部类编译后.class文件命名:外部类$内部类.class 2.静态内部类 静态内部类中,只能直接访问外部类的静态成员,如果需要调用非静态成员,可以通过对象实例 静态内部类对象实例时,可以不依赖于外部类对象 可以通过外部类.内部类.静态成员的方式,访问内部类中的静态成员 当内部类属性与外部类属性同名时,默认直接调用内部类中的成员; 如果需要访问外部类中的静态属性,则可以通过 外部类.属性 的方式; 如果需要访问外部类中的非静态属性,则可以通过 new 外部类().属性的方式; 3.方法内部类 定义在外部类方法中的内部类,也称为局部内部类。 image.png 方法的约束对方法内部类同样有效。 定义在方法内部,作用范围也在方法内 和方法内部成员使用规则一样,class前面不可以添加public、private、protected、static 类中不能包含静态成员 类中可以包含final、abstract修饰的成员 4.匿名内部类 匿名内部类 public static void main(String[] args) { PersonTest test=new PersonTest(); test.getRead(new Person(){ { //构造代码块 } @Override public void read() { System.out.println("男生喜欢看科幻类书籍"); } }); test.getRead(new Person(){ @Override public void read() { System.out.println("女生喜欢读言情小说"); } }); } } 匿名内部类没有类型名称、实例对象名称 编译后的文件命名:外部类$数字.class 无法使用private、public、protected、abstract、static修饰 无法编写构造方法,可以添加构造代码块 不能出现静态成员 匿名内部类可以实现接口也可以实现继承父类,但是不可兼得 如果内容对你有帮助,记得关注作者给个赞哦~,后续会持续更新。

优秀的个人博客,低调大师

Java入门系列-17-多态

这篇文章贯穿游戏中的一些功能带你掌握多态的使用 为什么要使用多态 在一款对战类游戏中(如有雷同纯属巧合),有两个不同的法师英雄:小乔、妲己。两个法师英雄的都有攻击的方法,小乔的攻击伤害为10,消耗魔法20。妲己的攻击伤害为15,消耗魔法30。玩家可以操作两个英雄进行攻击,下面看看实现的代码。 父类-英雄:whyusepolymorphic.Hero.java package whyusepolymorphic; public class Hero { private int magicPoint;//魔法值 private int hurt;//伤害 private String name;//姓名 public Hero(int magicPoint, int hurt, String name) { super(); this.magicPoint = magicPoint; this.hurt = hurt; this.name = name; } public int getMagicPoint() { return magicPoint; } public void setMagicPoint(int magicPoint) { this.magicPoint = magicPoint; } //省略属性的 getter 和 setter 方法 } 子类-小乔:whyusepolymorphic.LittleJoe.java package whyusepolymorphic; public class LittleJoe extends Hero { public LittleJoe(int magicPoint, int hurt, String name) { super(magicPoint, hurt, name); } //攻击的方法 public void attack() { System.out.println(this.getName()+" 发动攻击,伤害为:"+this.getHurt() +"。消耗 20的魔法值"); this.setMagicPoint(getMagicPoint()-20);//魔法值-20 } } 子类-妲己:whyusepolymorphic.Daji.java package whyusepolymorphic; public class Daji extends Hero{ public Daji(int magicPoint, int hurt, String name) { super(magicPoint, hurt, name); } public void attack() { System.out.println(this.getName()+" 发动攻击,伤害为:"+this.getHurt() +"。消耗 30的魔法值"); this.setMagicPoint(getMagicPoint()-30);//魔法值-30 } } 玩家:whyusepolymorphic.Player.java package whyusepolymorphic; public class Player { public void play(LittleJoe littleJoe) { littleJoe.attack(); } public void play(Daji daji) { daji.attack(); } } 上面代码完整的实现了要求中的功能,那我们知道英雄不可能就这几个,后期如果添加新的魔法英雄,伤害不一样,怎么办? 我们可以添加新的类,实现攻击的方法,修改玩家类添加操作英雄的方法。这个方式可以完成 Hero 扩展的需求,但是后面有更多的 Hero 添加进来,我们维护起来就不是那么方便了。 研究上面的代码我们发现,Player 类中的 play 方法的参数都是 Hero 类的子类,能否使用一个 play(Hero hero) 方法操作所有的英雄?使用多态就能够实现这种优化设计。 什么是多态 简明扼要,多态就是多种形态。在自然界中碳的多态就有石墨、钻石等,剪这个动作就有剪纸、剪头发等。同一个操作,由于条件的不同,产生的结果也不同。 那么在程序中的多态,就是指同一个引用类型,使用不同的实例而执行不同的操作(父类引用指定子类对象 Hero h=new Daji();)。 如何实现多态 实现多态的步骤: 1.编写具有继承关系的父类和子类 2.子类重写父类方法 3.使用父类的引用指向子类的对象 父类作为方法形参实现多态 使用多态优化上面代码 修改 Hero.java 添加攻击的方法 package whyusepolymorphic; public class Hero { //省略属性和构造方法 //攻击的方法 public void attack() { System.out.println(this.getName()+" 发动攻击,伤害为:"+this.getHurt() +"。消耗 20的魔法值"); this.setMagicPoint(getMagicPoint()-20);//魔法值-20 } //省略 getter 和 setter 方法 } 两个子类不用修改 修改玩家类 Player.java 将 play方法的参数设为父类 package whyusepolymorphic; public class Player { public void play(Hero hero) { hero.attack(); } } 修改测试类 package whyusepolymorphic; public class TestPlay { public static void main(String[] args) { Player p=new Player(); Hero daji=new Daji(100,15,"妲己"); p.play(daji); System.out.println(daji.getName()+" 剩余魔法:"+daji.getMagicPoint()); Hero littleJoe=new LittleJoe(100,10,"小乔"); p.play(littleJoe); System.out.println(littleJoe.getName()+" 剩余魔法:"+littleJoe.getMagicPoint()); } } 父类作为返回值实现多态 玩家购买英雄使用多态实现,购买的方法有返回值,返回购买后的英雄,父类作为返回值实现这个功能。 修改玩家类 Player.java 添加获取英雄的方法 package whyusepolymorphic; public class Player { public void play(Hero hero) { hero.attack(); } public Hero getHero(int id) { if(1==id) { return new Daji(100,15,"妲己"); }else if(2==id){ return new LittleJoe(100,10,"小乔"); }else { System.out.println("没有这个英雄"); return null; } } } 测试类 package whyusepolymorphic; import java.util.Scanner; public class TestPlay { public static void main(String[] args) { Player p=new Player(); System.out.println("欢迎来到英雄商店,请选择要购买的英雄:1.妲己2.小乔"); Scanner input=new Scanner(System.in); int id=input.nextInt(); Hero h=p.getHero(id); if(null!=h) { h.attack(); } } } 父类到子类的转换 如果子类中有一些子类特有的方法,父类引用不能调用子类的特有的方法。 向 Daji.java 中添加一个方法 queenWorship package whyusepolymorphic; public class Daji extends Hero{ //省略构造方法及之前其他方法 public void queenWorship() { System.out.println("释放大招:女王崇拜"); } } 向 LittleJoe.java 中添加一个方法 dazzlingStar package whyusepolymorphic; public class LittleJoe extends Hero { //省略构造方法及之前其他方法 public void dazzlingStar() { System.out.println("释放大招:星华缭乱"); } } 在 Player.java 中添加 bigMove 方法 package whyusepolymorphic; public class Player { //省略构造方法及之前其他方法 public void bigMove(Hero hero) { hero.dazzlingStar(); } } 发现代码 hero.dazzlingStar(); 报错 那么这个时候就需要将父类转换为子类(强制类型转换) Hero joe=new LittleJoe(100,10,"小乔"); Daji daji=(Daji) joe; 但是直接这样写也会报错,用 instanceof 运算符可以保证不会转换错误 语法:对象 instanceof 类或接口 instanceof通常和强制类型转换结合使用 修改 Player.java 中的 bigMove 方法 public void bigMove(Hero hero) { if (hero instanceof Daji) { ((Daji)hero).queenWorship(); }else if(hero instanceof LittleJoe) { ((LittleJoe)hero).dazzlingStar(); } } 在 main 方法中编写测试代码 Player p=new Player(); p.bigMove(new LittleJoe(100,10,"小乔")); p.bigMove(new Daji(100,15,"妲己")); 本人能力和水平有限,欢迎在文章下方给建议 搜索关注公众号「享智同行」,第一时间获取技术干货

优秀的个人博客,低调大师

Java入门系列-16-继承

这一篇文章教给新手学会使用继承,及理解继承的概念。掌握访问修饰符、掌握 final 关键字的用法。 继承 为什么要使用继承 首先我们先看一下这两个类: public class Teacher { private int teachingAge; private String name; private int age; public void teach() { } public void seyHi() { System.out.println("我是:"+this.name); } } public class Student { private int studentNo; private String name; private int age; public void learn() { } public void seyHi() { System.out.println("我是:"+this.name); } } Student 类和 Teacher 类中有一些相同的属性和方法,这些都属于重复代码,当一个程序中有大量的类时,就会产生大量的重复代码。这些重复的代码能不能抽取出来然后供其他类使用以简化呢,那就是使用继承。 使用继承优化之后: 创建 inherit 包 父类:(公共代码类) package inherit; public class People { private String name; private int age; public void sayHi() { System.out.println("我是:"+this.name); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } 子类:Student.java package inherit; public class Student extends People{ private int studentNo; public void learn() { System.out.println("学习课程"); } public int getStudentNo() { return studentNo; } public void setStudentNo(int studentNo) { this.studentNo = studentNo; } } 子类:Teacher.java package inherit; public class Teacher extends People{ private int teachingAge; public void teach() { System.out.println("教授课程"); } public int getTeachingAge() { return teachingAge; } public void setTeachingAge(int teachingAge) { this.teachingAge = teachingAge; } } 测试类: package inherit; public class TestInherit { public static void main(String[] args) { //创建Student对象 Student stu=new Student(); stu.setName("张三");//父类中继承过来的方法 stu.learn();//子类中特有的方法 stu.sayHi(); //创建Teacher对象 Teacher teacher=new Teacher(); teacher.setName("汤尼"); teacher.setTeachingAge(2);//子类中特有的方法 teacher.sayHi(); } } 观察上面示例代码我们发现: 1.子类的公共代码都可以放在父类中 2.子类可以有自己独有的方法和属性 3.子类一旦继承父类就会拥有父类的属性和方法 4.将公共代码放入父类,更方便统一修改代码 继承的语法 关键字:extends 1.编写父类 public class 父类{ //公共的属性和方法 } 2.编写子类,继承父类 public class 子类 extends 父类{ //子类特有的属性和方法 } 子类只能继承一个父类 子类访问父类成员 子类要想访问父类的成员要使用 super 关键字,super 代表父类对象 访问父类构造方法: super();//访问无参构造 super(参数);//访问有参构造 访问父类属性: super.name; 访问父类方法: super.print(); 访问父类构造,必须在子类构造方法中调用,必须是第一句 super 只能出现在子类的方法和构造方法中 super 不能访问父类的 private 成员 敲一敲:访问父类成员 创建包 visitparent 后在报下创建如下类父类 package visitparent; public class Animal { private String name; private int legs; public Animal() { this.name="无名"; this.legs=4; } public Animal(String name,int legs) { this.name=name; this.legs=legs; } public void eat(String food) { System.out.println(name+" 吃食物:"+food); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getLegs() { return legs; } public void setLegs(int legs) { this.legs = legs; } } 子类 package visitparent; public class Cat extends Animal{ private String hairColor;//毛发颜色 private int age; public Cat () { super();//调用父类无参 } public Cat(String name,int legs,String hairColor,int age) { super(name, legs);//这里调用相当于重用父类构造方法了 this.hairColor=hairColor; this.age=age; //super(name, legs);//去掉注释试试 //this.name="无名";//去掉注释试试 } public void catchMouse() { System.out.println(super.getName()+":抓老鼠"); } public void paly() { System.out.println(super.getName()+" 玩累了。"); super.eat("小鱼干"); } public String getHairColor() { return hairColor; } public void setHairColor(String hairColor) { this.hairColor = hairColor; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } 子类不能继承父类的 private 成员 子类不能继承不同包使用默认访问权限的成员(默认访问权限就是不写访问修饰符) 子类不能继承父类的构造方法 多重继承的执行流程 在创建子类的时候父类在做什么? 下面创建3个类观察执行流程,C类继承B类,B类继承A类。 A.java public class A { public A() { System.out.println("A类的无参构造函数执行"); } } B.java public class B extends A{ public B() { System.out.println("B类的无参构造函数执行"); } } C.java public class C extends B{ public C() { System.out.println("C类的无参构造函数执行"); } } TestRunFlow.java 测试类,展示运行结果 public class TestRunFlow { public static void main(String[] args) { C c=new C(); } } 运行结果为: A类的无参构造函数执行 B类的无参构造函数执行 C类的无参构造函数执行 如果子类构造方法通过 super 显式调用父类相应构造方法,则不执行父类无参构造方法 子类构造方法默认会调用父类无参构造方法 调用父类无参构造方法,一直到执行顶级父类Object类的的无参构造方法为止 根据以上规则,判断下面的代码是否能编译通过 父类 public class Pet { private String name; public Pet(String name) { this.name=name; } } 子类 public class Dog extends Pet{ } 答案是不能,父类中只有有参构造方法没有无参构造方法,子类中没有任何代码默认有一个隐式无参构造方法,子类无参构造方法默认调用父类无参构造方法,然而父类中没有,所有在子类中报错。 解决办法:1.在父类中显式添加无参构造方法,2.在子类构造方法中显式调用父类有参构造方法。 java 中的访问修饰符 访问修饰符 protected 能修饰属性和方法,修饰后本类、子类、同包可以访问。 访问修饰符 本类 同包 子类 其他 private √ 默认(friendly) √ √ protected √ √ √ public √ √ √ √ 方法重写 在"继承优化后"的代码中,Teacher 继承了 People 类,(忘记代码可以翻回去再看一遍) People 类中有个一个打招呼的方法 sayHi() 用于输出人的名字,但是 Teacher 调用这个方法并不能打印出 Teacher 的属性 teachingAge 的值,但是我们还想用这个方法实现这个功能,应该怎么办呢? 我们可以使用 方法重写 解决这个问题,修改子类 Teacher 中的代码,下面看一下使用方法重写后的效果。 Teacher.java package inherit; public class Teacher extends People{ //省略其他属性 @Override public void sayHi() { System.out.println("我是:"+super.getName()+" ,从事教育行业 "+this.teachingAge+" 年了。"); } //省略其他方法、getter、setter } 在 Eclipse 中重写某方法的快捷键是 Alt+Shift+S+V ,按完后选择要重写的方法 在 Idea 中重写某方法的快捷键是 Ctrl+O ,按完后选择要重写的方法 @Override 注解的作用, 用来检测是否符合重写规则,不符合重写规则将报错,这个注解可以不写 构造方法不能重写,因为构造方法不能被继承 方法重写的规则: 1.方法名相同 2.参数列表相同 3.返回值类型相同或者是其子类 4.访问权限不能严于父类 final 关键字的使用 1.final 修饰变量后变为常量 private static final long serialVersionUID = -6849794470754667710L; 2.final 修饰类后,该类不能被继承 package java.lang; public final class Math { //省略属性和方法…… } 3.final 修饰方法后,该方法不能被重写 public final void teach() { System.out.println("教授课程"); } 4.final 修饰创建的对象后,该对像不能再次实例化(可以修改属性) final Teacher teacher=new Teacher(); teacher.setName("汤尼"); //teacher=new Teacher();//去掉注释试试 String 类就是一个典型的被 final 修饰的类 搜索关注公众号「享智同行」,第一时间获取技术干货

优秀的个人博客,低调大师

Java入门系列-15-封装

为什么要封装 Student stu=new Student(); stu.age=-10; 上面的代码中 age 属性被随意访问,容易产生不合理的赋值 什么是封装 封装:将类的某些信息隐藏在内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。 封装是面向对象三大特征之一 封装后隐藏了类的实现细节,方便我们加入控制语句保证数据安全性,方便修改实现。 Java 中实现封装可以用以下3步实现: 1.修改属性的可见性,设为 private (类外部无法访问) 2.创建共有的 getter/setter 方法用于属性读写 3.在 getter/setter 方法中加入属性控制语句 public class Student { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { if(age>0&&age<=100) {//年龄大于0小于100 this.age = age; }else { this.age=18;//默认值 } } public static void main(String[] args) { Student stu1=new Student(); //给属性赋值 stu1.setAge(10); stu1.setName("张三"); //使用属性的值 System.out.println(stu1.getName()+" 的年龄为:"+stu1.getAge()); Student stu2=new Student(); stu2.setAge(110); stu2.setName("李四"); System.out.println(stu2.getName()+" 的年龄为:"+stu2.getAge()); } } 在使用 private 关键字修饰属性之后,就不能再直接访问属性了,而是需要通过 getter 和 setter 方法进行取值和赋值。 在 Eclipse 中可以使用 Shift+Alt+S+R 自动生成 getter/setter 在 Idea 中使用 Alt+Insert 后选择 Getter and Setter 搜索关注公众号「享智同行」,第一时间获取技术干货

优秀的个人博客,低调大师

scala入门之编写scala脚本

尽管scala的设计目的是帮助程序员建造大型系统。但它也能适应于制造小型的脚本。例如把以下代码放在hello.scala文件中: println("Hello,world,form ascript!") 然后运行: scala脚本的命令行参数保存在名为args的scala数组中。scala里,数组以0开始,可以通过在括号里指定索引值来访问数组元素。scala里数组 args 的第一个元素是:args(0),而不是像Java那样的:args[0]。现在,把以下内容写到新文件:helloarg.scala中测试一下: //向第一个参数打问好 println("Hello, " + args(0) + "!") 然后运行: 这条命令里,命令行参数“FHD”被传递给脚本,并通过访问args(0)获得。请注意这个脚本包含了一条注释。scala编译器忽略从//开始到行尾截止的以及在/* 和 */之间的字符。下面再举一个例子,如创建一个名为test.scala的脚本文件: var i = 0; while(i < args.length){ if(i != 0) print(" ") print(args(i)) i += 1; } println() 运行结果: 注意: Java的++i 和 i++ 在scala里不能使用的,要在scala里得到同样效果,必须要么写成: i = i + 1,要么写成: i += 1。 scala和Java一样,必须把while或if的布尔表达式放在括号里。 scala和Java一样,如果代码块仅有一行语句,就像上例中的 if 语句,那么花括号就可以不写。 尽管scala也和Java一样用分号分隔语句,但是scala的分号经常是可选的。 本文来自云栖社区合作伙伴“开源中国” 本文作者:柳哥 原文链接

优秀的个人博客,低调大师

springboot整合elasticsearch全文检索入门

只是简单的整合介绍 安装 下载elasticsearch与kibana https://www.elastic.co/start 依赖 springBootVersion = '2.0.5.RELEASE' compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-elasticsearch' //请与spring-boot-starter-data-elasticsearch的jar包版本一致 compile('org.elasticsearch.client:transport:5.6.11') springBoot 2.0.5.RELEASE 起步依赖的elasticsearch的版本是 5.6.11 配置 可在application.yml中配置 spring: data: # 全文检索 elasticsearch elasticsearch: cluster-name: elasticsearch #节点名称 cluster-nodes: 127.0.0.1:9300 #节点地址 repositories: enabled: true 也可以通过java代码进行配置 package com.futao.springmvcdemo.foundation.configuration import org.elasticsearch.client.transport.TransportClient import org.elasticsearch.common.settings.Settings import org.elasticsearch.common.transport.InetSocketTransportAddress import org.elasticsearch.transport.client.PreBuiltTransportClient import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories import java.net.InetAddress /** * @author futao * Created on 2018/10/22. * ElasticSearch全文检索配置类 * 可替代配置文件中的配置 */ @Configuration @EnableElasticsearchRepositories(basePackages = ["com.futao.springmvcdemo.dao"]) open class ElasticSearchConfiguration { @Bean open fun client(): TransportClient { val node = InetSocketTransportAddress( InetAddress.getByName("127.0.0.1"), 9300) val settings = Settings.builder() .put("cluster.name", "springboot-elasticsearch") //集群名称可以在\elasticsearch\config\elasticsearch.yml中配置 .build() return PreBuiltTransportClient(settings).addTransportAddress(node) } } 名词解释 elasticsearch中的名词与mysql中的名字对比 使用 个人理解:相当于mysql的建表,程序跑起来之后会建立相应的index与type,后续程序中就可以使用该类型的index与type进行crud package com.futao.springmvcdemo.model.entity; import org.springframework.data.elasticsearch.annotations.Document; /** * @author futao * Created on 2018/10/20. * 文章 * indexName=database * type=table * row=document * colnum=field */ @Document(indexName = "futao", type = "article") public class Article extends BaseEntity { /** * 标题 */ private String title; /** * 简介 */ private String description; /** * 内容 */ private String content; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } } 插入数据 Dao层 package com.futao.springmvcdemo.dao.impl import com.futao.springmvcdemo.model.entity.Article import org.springframework.data.elasticsearch.repository.ElasticsearchRepository /** * @author futao * Created on 2018/10/22. */ interface ArticleSearchDao : ElasticsearchRepository<Article, String> { } Service层 package com.futao.springmvcdemo.service.impl import com.alibaba.fastjson.JSONObject import com.futao.springmvcdemo.dao.ArticleDao import com.futao.springmvcdemo.dao.impl.ArticleSearchDao import com.futao.springmvcdemo.foundation.LogicException import com.futao.springmvcdemo.model.entity.Article import com.futao.springmvcdemo.model.entity.constvar.ErrorMessage import com.futao.springmvcdemo.service.ArticleService import com.futao.springmvcdemo.utils.currentTimeStamp import com.futao.springmvcdemo.utils.getFieldName import com.futao.springmvcdemo.utils.uuid import org.elasticsearch.client.Client import org.elasticsearch.index.query.QueryBuilders import org.springframework.data.redis.core.RedisTemplate import org.springframework.stereotype.Service import javax.annotation.Resource /** * @author futao * Created on 2018/10/20. */ @Service open class ArticleServiceImpl : ArticleService { @Resource private lateinit var elasticsearch: ArticleSearchDao @Resource private lateinit var client: Client override fun list(): List<Article> { val list = articleDao.list() elasticsearch.saveAll(list) return list } /** * 全文检索 */ override fun search(key: String): ArrayList<Article> { val hits = client.prepareSearch("futao") .setTypes("article") .setQuery( QueryBuilders .boolQuery() .should(QueryBuilders.matchQuery(Article::getContent.getFieldName(), key)) .should(QueryBuilders.matchQuery(Article::getTitle.getFieldName(), key)) .should(QueryBuilders.matchQuery(Article::getDescription.getFieldName(), key)) ) .execute() .actionGet() .hits val list: ArrayList<Article> = arrayListOf() hits.forEach { it -> list.add(JSONObject.parseObject(it.sourceAsString, Article::class.java)) } return list } } controller层 package com.futao.springmvcdemo.controller.business; import com.futao.springmvcdemo.model.entity.Article; import com.futao.springmvcdemo.model.entity.SingleValueResult; import com.futao.springmvcdemo.service.ArticleService; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.List; /** * @author futao * Created on 2018/10/20. */ @RestController @RequestMapping(path = "article", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public class ArticleController { @Resource private ArticleService articleService; /** * 新增文章 * * @param title * @param desc * @param content * @return */ @PostMapping(path = "add") public SingleValueResult add( @RequestParam("title") String title, @RequestParam("desc") String desc, @RequestParam("content") String content ) { articleService.add(title, desc, content); return new SingleValueResult("success"); } /** * 文章列表 * * @return */ @GetMapping("list") public List<Article> list() { return articleService.list(); } /** * 全文检索 * * @param key * @return */ @GetMapping("search") public List<Article> search(@RequestParam("key") String key) { return articleService.search(key); } } 在启动项目之前如果程序有抛出java.lang.IllegalStateException: availableProcessors is already set to [4], rejecting [4]异常,则需要在启动类中添加: package com.futao.springmvcdemo; import com.alibaba.fastjson.parser.ParserConfig; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.cache.annotation.EnableCaching; import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories; /** * @author futao * ServletComponentScan 开启servlet和filter */ @SpringBootApplication @ServletComponentScan @MapperScan("com.futao.springmvcdemo.dao") @EnableCaching //@EnableAspectJAutoProxy @EnableElasticsearchRepositories(basePackages = "com.futao.springmvcdemo") public class SpringmvcdemoApplication { public static void main(String[] args) { /** * 添加elasticsearch之后发生异常的解决方案 * Springboot整合Elasticsearch 在项目启动前设置一下的属性,防止报错 * 解决netty冲突后初始化client时会抛出异常 * java.lang.IllegalStateException: availableProcessors is already set to [4], rejecting [4] */ System.setProperty("es.set.netty.runtime.available.processors", "false"); SpringApplication.run(SpringmvcdemoApplication.class, args); /** * redis反序列化 * 开启fastjson反序列化的autoType */ ParserConfig.getGlobalInstance().setAutoTypeSupport(true); } } 测试 启动项目,可以在health中查看到相关的健康状况 list接口请求(把数据放入elasticsearch中) 现在可以在kibana中查看到上面存入的数据 也可以进行简单的搜索测试 调用search接口测试 elasticsearch数据的存放位置(删除该文件夹下的数据即删除了所有的索引) 多的不说了,跟之前项目中用过的Hibernate Search很像,不过elasticsearch也是在架构层面实现的全文索引,elasticsearch可以部署在其他服务器上,减轻主服务器的压力,并通过http restful api的形式与主程序进行协调工作。elasticsearch一般通过集群方式进行部署,横向扩展非常简单,甚至只需要改几行配置就行。

优秀的个人博客,低调大师

Java入门系列-10-数组

这篇文章为你搞懂2个问题 1.什么是数组,数组是干嘛用的? 2.数组如何使用? 考试结束后,老师给二狗安排了一项任务,统计班里40名同学的平均分。按照我们之前的做法,我们可以定义40个变量然后再相加除以40求出平均分,但是这样太繁琐了,有没有更好的办法呢?那就是使用 数组。 数组 数组其实也是一个变量,顾名思义存储了一组相同类型的数据,声明一个数组就是在内存空间中分配出一连串的空间。 使用数组需要四个步骤: 1.声明数组 int[] a; 2.分配空间 a=new int[5]; 3.赋值 a[0]=8; 4.处理数据 a[0]=a[0]*10; 数组中的元素通过下标进行访问,下标从0开始 数组长度是在分配完空间后是固定不变的 数组中所有的元素必须是相同的数据类型 1.声明数组:告诉计算机数据类型是什么 语法: 数据类型 数组名[]; 数据类型[] 数组名; 敲一敲: public class DemoArray { public static void main(String[] args) { int[] score;//成绩 String[] name;//名字 } } 2.分配空间:告诉计算机分配几个连续的空间 语法: 数组名=new 数据类型[大小]; 或者 声明数组同时并分配空间: 数据类型[] 数组名=new 数据类型[大小]; 敲一敲: public class DemoArray { public static void main(String[] args) { int[] score;//成绩 String[] name;//名字 score=new int[40]; name=new String[40]; //声明变量同时并分配空间 int[] age=new int[40]; } } 3.赋值:向分配的空间中放数据 敲一敲: public class DemoArray { public static void main(String[] args) { int[] score;//成绩 String[] name;//名字 score=new int[40]; name=new String[40]; //声明变量同时并分配空间 int[] age=new int[40]; name[0]="张三";//向数组中第一个元素存放数据 name[1]="李四";//向数组中第一个元素存放数据 } } 但是这样一个一个去赋值太麻烦了 敲一敲:1.声明数组的同时赋值 public class DemoArray1 { public static void main(String[] args) { int[] score= {67,55,93};//自动确定长度为3 String[] name=new String[] {"张三","李四","王五"}; } } 敲一敲:2.使用循环从控制台获取信息并赋值 import java.util.Scanner; public class DemoArray2 { public static void main(String[] args) { Scanner input=new Scanner(System.in); int[] score=new int[40]; for (int i = 0; i < score.length; i++) { score[i]=input.nextInt(); } } } length 是数组的属性,用于获取数组的长度 4.处理数据 敲一敲:遍历数组 public class DemoEachArray { public static void main(String[] args) { String[] name= {"香蕉","菠萝","西瓜"}; for (int i = 0; i < name.length; i++) { String temp=name[i]; System.out.println(i+" "+temp); } } } 可以打印数组,也可重新赋值等操作 工具类Arrays Arrays类包含操作数组的各种方法,使用这个类需要加入一行代码 import java.util.Arrays; 引入后使用。 方法名 说明 sort() 对指定的数组按数字升序进行排序。 toString() 返回指定数组内容的字符串表示形式。 copyOf() 复制指定的数组到一个新数组,并指定新数组的长度 敲一敲:sort的使用 import java.util.Arrays; public class DemoArraysSort { public static void main(String[] args) { int[] ages= {33,18,37,55,3}; Arrays.sort(ages); for(int i=0;i<ages.length;i++) { System.out.println(i+" "+ages[i]); } } } 敲一敲:toString的使用 import java.util.Arrays; public class DemoArraysToString { public static void main(String[] args) { String[] name= {"张三","李四","王五","赵六"}; String result=Arrays.toString(name); System.out.println(result); double[] money= {55.4,34,66,23.3}; System.out.println(Arrays.toString(money)); } } 敲一敲:copyOf的使用 import java.util.Arrays; public class DemoArraysCopyOf { public static void main(String[] args) { int[] ages= {33,18,37,55,3}; int[] newArray1=Arrays.copyOf(ages, 3); System.out.println("新数组:"+Arrays.toString(newArray1)); int[] newArray2=Arrays.copyOf(ages,8); System.out.println("新数组:"+Arrays.toString(newArray2)); } } 使用 copyOf() 时,如果指定的副本数组的长度小于源数组的长度,后面的元素都将被截断。如果指定的副本数组的长度大于源数组的长度,多出的元素都将使用默认值。 数组元素默认值 如果一个数组已经指定了长度,但是没有给元素赋值,那么没有赋值的元素都会有默认值。 类型 默认值 String null int 0 double 0.0 boolean false Object null 敲一敲:体验各种类型的默认值 import java.util.Arrays; public class DemoDefaultValue { public static void main(String[] args) { String[] name=new String[10]; System.out.println("字符串:"+Arrays.toString(name)); int[] age=new int[10]; System.out.println("整数:"+Arrays.toString(age)); double[] money=new double[10]; System.out.println("小数:"+Arrays.toString(money)); Object[] obj=new Object[10]; System.out.println("对象:"+Arrays.toString(obj)); boolean[] results=new boolean[10]; System.out.println("布尔值:"+Arrays.toString(results)); char[] chrs=new char[10]; System.out.println("字符:"+Arrays.toString(chrs)); System.out.println((int)chrs[0]);//字符对应的整数 } } 试一试: 1.从控制台中输入5个人的年龄,存入数组中,求出最小的年龄 2.将一组乱序的字符排序后,进行升序和逆序输出 搜索关注公众号「享智同行」,第一时间获取技术干货,公众号回复010 获取本次练习答案!

优秀的个人博客,低调大师

Webpack 10分钟入门

可以说现在但凡开发Single page application,webpack是一个不可或缺的工具。 WebPack可以看做是一个模块加工器,如上图所示。它做的事情是,接受一些输入,经过加工产生一些输出。 输入是我们web前端项目的模块文件,通常情况下这些文件都不能直接被浏览器的JavaScript执行引擎所执行。 输出是经过webpack加工后的能被浏览器使用的javascript和静态资源文件。比如ES6的js转成ES5的js,CSS预处理器文件转成CSS文件等等。 我们来动手做一个具体的例子。这个例子只花费10分钟时间,就能让我们熟悉webpack的基本用法。 1. 新建一个文件夹,首先用npm init命令创建一个package.json: 在下面使用命令行npm install --save-dev webpack,安装webpa

优秀的个人博客,低调大师

小游戏入门到精通OR放弃?

这里说的小游戏是QQ玩一玩,后面会写微信小游戏... 0、体验QQ轻游戏 需要使用Android手机 登录手Q开启厘米秀 侧滑点击人物形象或者选择任意一好友点击**「+」滑拔一下找到「厘米秀」** 搜索厘米秀 申请体验资格 开启厘米秀 侧滑 好友点「+」或者直接点击人物 游戏入口页 1、平台申请账号 注册很简单,使用已有Q号登录「厘米游戏」开放平台按照流程提交资料审核即可 。开发者接入官方说明文档 「厘米游戏」 开放平台注册提交资料的同时会注册一个相关联的**「QQ服务号」**。游戏中显示的用户信息是通过后台静默授权「QQ服务号」后再通过用户相关的接口获得,这点与微信公众号以及微信小游戏类似。 一句话概括:目前暂未对个人开放,现阶段为邀请码模式。但如果你有好的IP资源或者优秀开发团队是比较好申请的。 与 「微信小游戏」 做比较目前来看最大的优势就是 现阶段游戏中集成广告所得广告费用平台不分成 游戏评级高官方可以让游戏上中心化首页推荐位 上线游戏都需要 「游戏自审自查报告」、「计算机软件著作权登记证书」,如需内购需要提供 「广电总局版号批文」 以及 「文化部备案信息」 2、环境搭建 QQ玩一玩(轻游戏)开发环境搭建与调试 如果使用了第三方引擎Mac电脑非必须。 3、第三方引擎推荐 第三方引擎的实现方式为基于 bricks 的 webGL 接口进行封装,具有较高的灵活性,但渲染性能会欠缺。 如开发者对性能要求更高,推荐使用bricks引擎的原生渲染。 注意: iOS 在手 Q 770 版本禁用了 webGL,会导致界面卡在 99% 加载界面,开发者忽略 iOS 端表现,关注安卓端表现。 Cocos Creator 开发玩一玩说明文档 Egret Engine 开发玩一玩说明文档 LayaAir 引擎开发玩一玩说明文档 关于使用什么引擎来开发「轻游戏」或者「H5游戏」都有各自的说法。就像大家讨论Java是世界最好的语言一样。 世界上没有不出bug的程序,引擎或者IDE都或多或少存在一定的Bug以及局限性。请根据项目需求以及当下的环境酌情选择。 从现在的技术发展讨论egret和cocos的优缺点H5方面 小程序游戏选择 egret, cocos Creator 还是 layabox? 开发H5游戏引擎的选择:Egret或Laya? 本文示例使用的游戏引擎为Cocos Creator 4、QQ轻游戏常用功能介绍 4.1 获取用户信息 4.1.1 获取游戏全局变量 游戏启动后,引擎会为开发者写入名为GameStatusInfo的有关游戏的全局参数(类似于H5中windows对象),从中可获取有关用户标识符(openId)、游戏标识(gameId)、机型等参数。 详细参数对照表请移步至 官方参考文档-登录与鉴权 示例参考-- 获取手Q版本跳转其他游戏 if (cc.sys.platform != cc.sys.QQ_PLAY) { self.setTipMsg("请在QQ玩一玩环境下测试"); return; } if (BKTools.versionCompare(GameStatusInfo.QQVer, "7.7.0.0")) { BKTools.skipGame("2731"); } else { self.setTipMsg("手Q版本过低,请更新"); } 如何跳转其他游戏完整的代码后面会提到 4.1.2获取用户昵称 function getNick(callback) { BK.MQQ.Account.getNick(GameStatusInfo.openId, callback); } BKTools.getNick(function(openId, nick) { Global.nickName = nick; }); 4.1.3 获取用户图像 getHead() { let self = this; let absolutePath = "GameSandBox://_head/" + GameStatusInfo.openId + ".jpg"; let isExit = BK.FileUtil.isFileExist(absolutePath); cc.log(absolutePath + " is exit :" + isExit); //如果指定目录中存在此图像就直接显示否则从网络获取 if (isExit) { cc.loader.load(absolutePath, function (err, texture) { if (err == null) { self.head.getComponent(cc.Sprite).spriteFrame = new cc.SpriteFrame(texture); } }); } else { BK.MQQ.Account.getHeadEx(GameStatusInfo.openId, function (oId, imgPath) { cc.log("openId:" + oId + " imgPath:" + imgPath); var image = new Image(); image.onload = function () { var tex = new cc.Texture2D(); tex.initWithElement(image); tex.handleLoadedTexture(); self.head.getComponent(cc.Sprite).spriteFrame = new cc.SpriteFrame(tex); } image.src = imgPath; }); } }, // onLoad () {}, btn(event, data) { cc.log("点击了按钮"); if (cc.sys.platform == cc.sys.QQ_PLAY) { this.getHead(); } else { cc.log("请在QQ玩一玩平台中测试"); } }, 4.2 分享与邀请 QQ轻游戏分享方法比较多具体实现方式可以官方的分享相关文档。这里介绍常用的一种方式 多渠道分享。 /** * 获取分享信息 * @param {String} localPicPath */ function getShareInfo(localPicPath) { if (!localPicPath) { localPicPath = "GameRes://qrcode.png";//游戏资源包根目录存放图片qrcode.png } let summarys = ["文案1", "游戏太好玩了,玩得停不下来!", "游戏太刺激了,邀请还能领抱枕!", "文案2"]; let shareInfo = { summary: summarys[getRandomInt(0, 3)], picUrl: "http://h.hiphotos.baidu.com/image/pic/item/18d8bc3eb13533fa4dd573ada3d3fd1f40345bd6.jpg", //支持HTTPS extendInfo: Global.openId,//或者使用GameStatusInfo.openId localPicPath: localPicPath, //分享至空间、微信、朋友圈时需要的图。(选填,若无该字段,系统使用游戏对应的二维码) }; return shareInfo; } /** * 分享 * @param {*} shareInfo * @param {*} callback */ function toShare(shareInfo, callback) { if (cc.sys.platform == cc.sys.QQ_PLAY) { BK.QQ.share(shareInfo, function (retCode, shareDest, isFirstShare) { log("分享结果 retCode:" + retCode + " shareDest:" + shareDest + " isFirstShare:" + isFirstShare); if (retCode == 0) { if (callback) { callback(0); } if (shareDest == 0) { //聊天窗 log("成功分享至QQ"); } else if (shareDest == 1) { //空间 log("成功分享至空间"); } else if (shareDest == 2) { //微信 log("成功分享至微信"); } else if (shareDest == 3) { // 朋友圈 log("成功分享至朋友圈"); } } else if (retCode == 1) { if (callback) { callback(-1); } log("分享失败" + retCode); } else if (retCode == 2) { if (callback) { callback(-1); } log("分享失败,用户取消分享:" + retCode); } }); } else { if (callback) { callback(0); } } } 但这里有一个问题 点击右上角的「…」选择分享游戏,分享后图片不显示再次调用接口来实现分享时无任何影响 ,要想解决此问题自需要实现生命周期监听并实现onShare 方法 关于QQ玩一玩的默认分享问题 4.3 生命周期 /** * 游戏事件以及生命周期 */ function addGameEvent() { new BK.Game({ //游戏启动后 onLoad: function (app) { log("BK.Game.onLoad"); }, //进入点击最大化后 onMaximize: function (app) { log("BK.Game.onMaxmize"); }, //进入点击最小化后 onMinimize: function (app) { log("BK.Game.onMinmize"); }, //进入后台后响应 onEnterBackground: function (app) { log("BK.Game.onEnterbackground"); }, //回到前台后响应 onEnterForeground: function (app) { log("BK.Game.onEnterforeground"); }, //点击“分享游戏”后响应。(可选) onShare: function (app) { log("BK.Game.onShare"); return getShareInfo(); }, //分享成功 onShareComplete: function (app, retCode, shareDest, isFirstShare) { log("BK.Game.onShareComplete retCode:" + retCode + " shareDest:" + shareDest + " isFirstShare:" + isFirstShare); }, //进入点击关闭响应 onClose: function (app) { log("BK.Game.onClose"); }, //网络环境切换事件 onNetworkChange: function (app, state) { log("BK.Game.onNetworkChange:STATE :" + state); }, //全局异常监听 onException: function () { log("BK.Game.onException msg:" + this.errorMessage() + " ,stack:" + this.errorStacktace()); } }); } 4.4 支付与红包 支付接入比较简单,目前没有异步通知给开发者的接口,所有的逻辑都由玩一玩后台处理。支付接入步骤 平台上传道具资源(图片、描述、单价等) 道具申请上架 游戏内通过接口获取道具信息(道具ID、名称、图片等) 通过道具ID列表购买道具 具体流程实现参考官方文档-支付 据内部消息 发送B2C红 在今年国庆假期间将有一批轻游戏试水,有什么样的创意和玩法可以期待一下。红包总金额最低5W最高20W。 5、网络通讯 在 原生引擎开发指引 中可以了解到。网络方案可以使用原生引擎、或者三方引擎进行界面以及逻辑的搭建。 官方文档-网络功能 下面我会介绍 BK.HttpUtil:用于短连接 XMLHttpRequest:用于短连接 WebSocket:用于长连接 http get/post请求 BK.HttpUtil function BKGet(url, callback, custom) { let httpUtil = new BK.HttpUtil(url); httpUtil.setHttpMethod("get"); httpUtil.custom = custom; //绑定回调对象 httpUtil.requestAsync(callback.bind(httpUtil)); } 如果是POST请求,将httpUtil.setHttpMethod("get");设置为httpUtil.setHttpMethod("post"); //下载图片并保存在手机中 BKTools.BKGet("http://h.hiphotos.baidu.com/image/pic/item/18d8bc3eb13533fa4dd573ada3d3fd1f40345bd6.jpg", function (res, code) { cc.log("结果:" + code + " 渗透参数:" + this.custom); BK.FileUtil.writeBufferToFile("GameSandBox://test/test.jpg", res); }, "custom"); //普通的get请求 BKTools.BKGet("http://www.wanandroid.com/tools/mockapi/3461/Javen", function (res, code) { cc.log("结果:" + code + " 渗透参数:" + this.custom); if (code == 200) { let str = res.readAsString(); cc.log(str); let data = JSON.parse(str); if (data.code == 0) { self.setTipMsg("网络请求结果 Gitee:" + data.data.name); } else { self.setTipMsg("网络请求异常:" + data.msg); } } }, "请求返回字符串"); XMLHttpRequest /** * post 请求 * @param {*} url * @param {*} data * @param {*} callBack */ function post(url, data, callBack) { log("请求参数:" + data); var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { let status = xhr.status; if (xhr.readyState == 4 && status == 200) { var responseBody = xhr.responseText; log("响应的结果:" + responseBody); callBack(status, JSON.parse(responseBody)); } }; xhr.open("POST", url, true); xhr.send(data); } /** * get请求 * @param {*} url * @param {*} data * @param {*} callBack */ function get(url, data, callBack) { log("请求参数:" + data); var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { let status = xhr.status; if (xhr.readyState == 4 && status == 200) { var responseBody = xhr.responseText; log("响应的结果:" + responseBody); callBack(status, JSON.parse(responseBody)); } }; xhr.open("GET", url + "?" + encodeURIComponent(data), true); xhr.send(); } webSocket请求 如果是QQ玩一玩平台就是使用 BK.WebSocket,其他平台使用 标准的WebSocket //Script/common/WebSocket.js /** * @author Javen * @copyright 2018-09-22 17:32:21 javendev@126.com * @description webSocket工具组件 */ let Global = require("Global"); let BKTools = require("BKTools"); let WS_TYPE = cc.Enum({ BK_WS: 1, WEB_WS: 2, }); cc.Class({ extends: cc.Component, // properties: { // }, // onLoad () {}, start() { // this.schedule(function () { // if (this.hasConnected) { // } // }, 5); }, initWebSocket() { if (cc.sys.platform == cc.sys.QQ_PLAY) { this._ws = new BK.WebSocket("ws://" + Global.WEB_SOCKET.URL); this._wsType = WS_TYPE.BK_WS; } else { this._ws = new WebSocket("ws://" + Global.WEB_SOCKET.URL); this._wsType = WS_TYPE.WEB_WS; } this.addEventListener(this._ws); }, addEventListener(ws) { let self = this; ws.onopen = function (event) { self._isConnected = true; BKTools.log("onopen...."); }; ws.onerror = function (event) { self._isConnected = false; BKTools.log("onerror...."); }; ws.onclose = function (event) { self._isConnected = false; BKTools.log("onclose...."); }; if (self._wsType == WS_TYPE.BK_WS) { ws.onMessage = function (ws, event) { if (event.isBinary) { let buf = event.data; //将游标pointer重置为0 buf.rewind(); let ab = new ArrayBuffer(buf.length); let dv = new DataView(ab); while (!buf.eof) { dv.setUint8(buf.pointer, buf.readUint8Buffer()); } self.toHander(ab); } else { BKTools.log("BK.WebSocket data type is not binary"); } } } else { ws.onmessage = function (event) { if (event.data instanceof Blob) { let blob = event.data; var reader = new FileReader(); reader.readAsArrayBuffer(blob); reader.onload = function (e) { if (e.target.readyState == FileReader.DONE) { let result = reader.result; self.toHander(result); } } } else { BKTools.log("webSocket data type is not blob"); } }; } }, hasConnected() { return this._isConnected; }, toHander(buffer) { let self = this; let cmd = proto.UserCmdOutComonProto.deserializeBinary(buffer); switch (cmd.getId()) { case proto.UserCmdOutType.RECONNECTION_RESULT: BKTools.log("重连结果...."); break; case proto.UserCmdOutType.USER_CONNECT_SUCCESS: BKTools.log("客户端连接成功...."); break; case proto.UserCmdOutType.USER_LOGIN_SUCCESS: BKTools.log("反馈登录消息开始..."); break; case proto.UserCmdOutType.USER_LOGIN_SUCCESS_OVER: BKTools.log("反馈登录消息结束...."); let loginOver = proto.PlayerLoginOverProtoOut.deserializeBinary(buffer); //回调给请求页 Global.loginResponse(loginOver); break; default: break; } }, send(bytes) { this._ws.send(bytes); }, /** * 登录 */ toLogin() { if (!this.hasConnected()) { this.initWebSocket(); return; } let login = new proto.UserLoginProto(); login.setId(proto.UserCmdInType.USER_LOGIN); login.setToken(Global.WEB_SOCKET.TOKEN); this.send(login.serializeBinary()); }, // update (dt) {}, }); 如何使用? 将webSocket工具组件绑定到常驻节点,在通过cc.find查找常驻节点上的WebSocket组件 this._webSocket = cc.find("常驻节点名称").getComponent("WebSocket"); //调用封装的接口 this._webSocket.toLogin(); 6、跳转到其他游戏 跳转到其他游戏手Q 7.7.0 及以上才支持 /** * 判断手Q版本 * @param {String} ver1 7.1.1.1 * @param {String} ver2 6.3.3.3 */ function versionCompare(ver1, ver2) { ver1 = parseInt(ver1.replace(/\./g, "")); ver2 = parseInt(ver2.replace(/\./g, "")); if (ver1 >= ver2) { return true; } else { return false; } } /** * 跳转到其他游戏 * @param {Number} gameId */ function skipGame(gameId) { BK.QQ.skipGame(gameId, "扩展参数");//游戏启动时可以通过GameStatusInfo.gameParam获取 } 7、成绩上报与排行榜 官方文档-成绩上报与排行榜 最新版本接口示例 胜局积累-大到小 /** * 成绩上报 * @param {*} isWin * @param {*} callback */ function uploadScore(isWin, callback) { if (cc.sys.platform != cc.sys.QQ_PLAY) { if (callback) { callback(-1, "此接口只支持QQ玩一玩平台"); } return; } if (!isWin) { isWin = 0; } else { isWin = 1; } var data = { userData: [{ openId: GameStatusInfo.openId, startMs: Global.startGameTime.toString(), endMs: ((new Date()).getTime()).toString(), scoreInfo: { score: isWin, }, }, ], attr: { score: { type: 'rank', order: 3, } }, }; BK.QQ.uploadScoreWithoutRoom(1, data, function (errCode, cmd, data) { log("uploadScoreWithoutRoom callback cmd" + cmd + " errCode:" + errCode + " data:" + JSON.stringify(data)); if (callback) { callback(errCode, data); } }); } /** * 拉取排行榜数据 * @param {*} callback */ function getRankList(callback) { if (cc.sys.platform != cc.sys.QQ_PLAY) { if (callback) { callback(-1, "此接口只支持QQ玩一玩平台"); } return; } let attr = "score"; let order = 3; let rankType = 0; BK.QQ.getRankListWithoutRoom(attr, order, rankType, function (errCode, cmd, data) { log("getRankListWithoutRoom callback cmd" + cmd + " errCode:" + errCode); if (errCode != 0) { callback(errCode); return; } if (data) { let rankList = data.data.ranking_list; log("data not null " + rankList.length); log(JSON.stringify(data)); // rankList.forEach(element => { // log("....华丽的分割线...."); // log("score:" + element.score); // log("nick:" + element.nick); // log("....华丽的分割线...."); // }); if (callback) { callback(errCode, rankList); } } }); } 8、关注公众号 查询是否关注公众号 function checkPubAccountState(){ BK.QQ.checkPubAccountState(Global.PUIN ,function(errCode, cmd, data) { BK.Script.log(0,0," callback errCode = "+errCode+ " cmd = "+ cmd + " data = "+ data); if(data.is_follow == 1){ return true; }else{ return false; } }); } 进入公众号主页 /** * 关注公众号 */ function follow() { if (cc.sys.platform == cc.sys.QQ_PLAY) { BK.QQ.enterPubAccountCard(Global.PUIN); } } 如何获取 PUIN ?请移步至官方-公众号 9、广告 详细介绍请移步至官网-广告接入流程 简单的封装与使用 /** * 加载视频广告 */ function fetchVideoAd(videoType) { if (!videoType) { videoType = 0; } log("开始加载视频广告..." + videoType); BK.Advertisement.fetchVideoAd(videoType, function (retCode, msg, handle) { log("retCode:" + retCode + " msg:" + msg); //返回码0表示成功 if (retCode == 0) { Global.videoHandle = handle; //广告监听在业务逻辑中处理 } else { log("拉取视频广告失败error:" + retCode + " msg:" + msg); } }.bind(this)); log("加载了视频广告..."); } /** * 加载条幅广告 */ function fetchBannerAd() { BK.Advertisement.fetchBannerAd(function (retCode, msg, bannerHandle) { log("retCode:" + retCode + " msg:" + msg); if (retCode == 0) { Global.bannerHandle = bannerHandle; bannerHandle.onClickContent(function () { log("用户点击了落地页"); }); bannerHandle.onClickClose(function () { log("用户点击了X关闭广告"); }); } else { log("fetchBannerAd failed. retCode:" + retCode); } }.bind(this)); } function closeBannerAd() { log("关闭广告...."); if (Global.bannerHandle) { Global.bannerHandle.close(); Global.bannerHandle = undefined; } } function loadBannerAd() { if (cc.sys.platform == cc.sys.QQ_PLAY) { log("预加载Banner"); fetchBannerAd(); } } function loadVideoAd() { if (cc.sys.platform == cc.sys.QQ_PLAY) { log("预加载Video"); fetchVideoAd(); } } /** * @author Javen * @copyright 2018-09-26 15:53:52 javendev@126.com * @description 广告测试 */ let BKTools = require("BKTools"); var Global = require("Global"); cc.Class({ extends: cc.Component, properties: { }, // onLoad () {}, btnClick(event, data) { BKTools.log("点击了>" + data); if (data == 'loadVideo') { //如果需要判断是否加载成功可以在封装的函数中添加回调 BKTools.loadVideoAd(); } else if (data == 'showVideo') { if (Global.videoHandle) { this.jumpVideoAd(); } else { BKTools.log("无视频广告句柄"); BKTools.loadVideoAd(); } } else if (data == 'loadBanner') { BKTools.loadBannerAd(); } else if (data == 'showBanner') { if (Global.bannerHandle) { this.showBannerAd(); } else { BKTools.log("无条幅广告句柄"); BKTools.loadBannerAd(); } } else if (data == 'closeBanner') { BKTools.closeBannerAd(); } else if (data == 'back') { cc.director.loadScene("welcome"); } }, jumpVideoAd() { let self = this; Global.videoHandle.jump(); Global.videoHandle.setEventCallack( function (code, msg) {}.bind(this), //关闭游戏(不再使用不需要监听) function (code, msg) { if (code == 0) { BKTools.log("达到看广告时长要求,可以下发奖励 endVide code:" + code + " msg:" + msg); //达到看广告时长要求,可以下发奖励 } else { BKTools.log("其他异常,比如播放视频是程序返回到后台"); } }.bind(this), function (code, msg) { BKTools.log("关闭视频webview endVide code:" + code + " msg:" + msg); //关闭视频webview }.bind(this), function (code, msg) { BKTools.log("开始播放视频 startVide code:" + code + " msg:" + msg); //开始播放视频 }.bind(this)); }, showBannerAd() { Global.bannerHandle.show(function (succCode, msg, handle) { if (succCode == 0) { BKTools.log("banner展示成功 home"); } else { BKTools.log("banner展示失败home msg:" + msg); } }); }, start() { }, // update (dt) {}, }); 10、源码 文中涉及到的代码以及案例已上传至 Gitee-Brickengine_Guide 完 到这里就介绍完了,个人能力有限如有错误欢迎指正如有遗漏欢迎补充。如有疑问欢迎留言一起交流讨论。

优秀的个人博客,低调大师

Python3 的入门安装

一、Python的重要性 目前越来越流行,常应用于运维自动化、云计算、虚拟化、机器智能等领域;国内大公司BAT,京东,网易等都会用到。国外的YouTube、Google、Yahoo甚至NASA 也都使用Python。 Python可以应用于Linux、Unix(苹果)、Windows; Linux自带Python;目前cent os 7自带的是Python2.7 二、Python的下载与安装(示例:Windows 7) 1、Python官网:https://www.python.org/ 根据操作系统及位数下载对应版本的安装文件。 其中executable installer为可执行文件安装包;web-based是在线安装包。 2、双击运行安装文件 python-3.6.4-amd64;选择自定义安装,注意勾选Add Python 3.6 to PATH, 因为后面不用再进行环境变量的设置了。自定义安装路径即可; 3、安装完成后,开始——运行——cmd,然后输入python,出现如图所示即表示安装成功。 4、Linux下安装Python3: 因为cent os 7中的 yum 是Python 2.7脚本;所以不建议使用yum安装,以免yum命令不能正常使用(或者需要修改Linux系统的配置文件profile才可以); 建议使用源码包进行安装。下载源码包、解压、编译安装; 5、Mac系统安装:下载dmg文件运行安装后拖动至应用程序即可; 三、编辑器的选择 1、Vim编辑器:支持自动补全功能,在编辑 Python中也支持自动补全,但是需要进行配置 2、可以使用 pycharm eclipse notepad++ 等;大型项目等推荐使用 pycharm 四、Pycharm 的下载安装及设置 1、官网下载地址:https://www.jetbrains.com/pycharm/ 提供收费版和教育研究免费版 2、双击运行安装,选择64位 3、初次使用(如果是个人版,需要激活 选择License server 输入http://gh0st.cc:1017) 也可以自己在公有云搭建服务。 搭建所需素材 https://pan.baidu.com/s/15i7CWnXJTySDn0nEOYkTpQ 五、pycharm的设置 1、设置python版本:Files—Settings—Project:Python3—Project Interpreter 2、代码通用抬头:Files—Settings—File and Code Templates—Python Script 写如下内容 #!/us/bin/env python # -*- coding:utf-8 -*- #@time:${DATE} ${TIME} #@Author:JSH #@File:${NAME}.PY 3、字体设置: Files—Settings—Editor—Font 六、第一个python小程序 1、Windows 如何运行python程序: 方法1:工具栏 ——Run——选择需要运行的文件 方法2:写完后点击鼠标右键,选择 run 0327 (推荐此方法) 方法3:ctrl+shift+F10 运行当前程序 方法4:右上角点击 2、Mac / Linux下如何运行? 例如已经编辑文件 1.py 则输入 ①Python 1.py ② chmod +x 1.py ③ ./1.py 即可运行 3、怎么在pycharm中不加input的情况下传参数: {0}.format( )

优秀的个人博客,低调大师

Redis入门教程(C#)

Redis是什么? Redis是一个开源的、使用C语言编写的、支持网络交互的、可基于内存也可持久化的Key-Value数据库。 补充概念: 持久化:是将程序数据在持久状态和瞬时状态间转换的机制。通俗的讲,就是瞬时数据(比如内存中的数据,是不能永久保存的)持久化为持久数据(比如持久化至数据库中,能够长久保存) Redis的安装、启动: 下载地址:https://github.com/MSOpenTech/redis/releases,可根据需要选择下载32位或者64位 这里我选择的是64位安装包: 然后解压安装包到指定目录。 接下来是Rdis的启动,打开一个cmd命令窗口,进入解压后的Redis目录,运行命令"redis-server.exe redis.windows.conf"即可启动Redis,启动后界面如下: 接下来介绍Redis的简单使用: 1.在VS 2017上新建一个项目,我这里创建的是控制台程序; 2.通过NuGet管理器安装ServiceStack.Redis库 3.新建一个测试类: public class Todo { public long Id { get; set; } public string Content { get; set; } public int Order { get; set; } public bool Done { get; set; } } 4.测试代码如下,此过程中不能关闭之前的cmd窗口,不然会无法访问服务器: static void Main(string[] args) { var redisManger = new RedisManagerPool("127.0.0.1:6379"); //Redis的连接字符串 var redis = redisManger.GetClient(); //获取一个Redis Client var redisTodos = redis.As<Todo>(); var newTodo = new Todo //实例化一个Todo类 { Id = redisTodos.GetNextSequence(), Content = "Learn Redis", Order = 1, }; redisTodos.Store(newTodo); //把newTodo实例保存到数据库中 增 Todo saveTodo = redisTodos.GetById(newTodo.Id); //根据Id查询 查 "Saved Todo: {0}".Print(saveTodo.Dump()); saveTodo.Done = true; //改 redisTodos.Store(saveTodo); var updateTodo = redisTodos.GetById(newTodo.Id); //查 "Updated Todo: {0}".Print(updateTodo.Dump()); redisTodos.DeleteById(newTodo.Id); //删除 var remainingTodos = redisTodos.GetAll(); "No more Todos:".Print(remainingTodos.Dump()); Console.ReadLine(); } 最终运行结果如下:

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册