首页 > 代码库 > java入门了解15

java入门了解15

1.批处理文件(bat)

  简单的说,批处理的作用就是自动的连续执行多条命令 .编写bat处理文件可以使用记事本的方式:

  常见批处理文件的命令:

    echo 表示显示此命令后的字符 

    tiltle 设置窗口的标题。

    echo off 表示在此语句后所有运行的命令都不显示命令行本身 

    color 设置窗体的字体颜色。

    @echo off相象,但它是加在每个命令行的最前面,表示运行时不显示这一行的命令行(只能影响当前行)。 

    pause 运行此句会暂停批处理的执行并在屏幕上显示Press any key to continue...的提示,等待用户按任意键后继续 

    rem 表示此命令后的字符为解释行(注释),不执行,只是给自己今后参考用的(相当于程序中的注释) 或者%注释的内容%

    %[1-9]表示参数,参数是指在运行批处理文件时在文件名后加的以空格(或者Tab)分隔的字符串

  例子:

2.对象拷贝

  一:浅拷贝:拷的都是栈中值

    拷贝对象需要实现Cloneable接口(其实这个接口没有方法只是起到标识的作用)

    起到效果:只是拷贝了成员,对于成员中的引用其他对象,拷贝只是栈中值而不是堆中值

  二:深拷贝:拷的都是堆中值就是实际的值

    原理:对象的深克隆就是利用对象的输入输出流将对象存到硬盘文件中再从文件中读取对象

    注意:所以让需要克隆的对象实现Serilization接口来完成对象存取操作ObjectInputStream,ObjectOutputStream

    起到作用:拷贝所有,引用对象的值也拷贝了

  三:例子

技术分享
/**
 * 对象深拷贝浅拷贝
 * @author Administrator
 *
 */
public class Copy {

    private static ObjectInputStream objectInputStream;


    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        //浅克隆
        Person p1=new Person("1", "小王", new Address("安徽"));
        Person p2=p1.clone();
        p1.id="2";
        p1.address.city="北京";
        System.out.println(p1.toString());//城市:都变为改变后的值北京
        System.out.println(p2.toString());//城市:都变为改变后的值北京
        //------浅拷贝引用成员拷贝的是栈中值----------//
        //深克隆
        Address address = new Address("广州");
        Person p3 = new Person("1","狗娃",address);
        writeObj(p3);
        Person p4  =readObj();
        
        p4.address.city = "长沙";
        System.out.println("p1:"+ p3);
        System.out.println("p2:"+ p4);
    }
    //文件写到硬盘中
    //再从文件中读取对象的信息
    public static Person readObj() throws ClassNotFoundException, IOException{
        FileInputStream fileInputStream = new FileInputStream("F:\\obj.txt");
        objectInputStream = new ObjectInputStream(fileInputStream);
        return (Person) objectInputStream.readObject();
        
    }
    
    
    //先要把对象写到文件上。
    public static void writeObj(Person p) throws IOException{
        //建立一个文件 的输出流对象
        FileOutputStream fileOutputStream  = new FileOutputStream("F:\\obj.txt");
        //建立对象的输出流
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        //把对象写出
        objectOutputStream.writeObject(p);
        //关闭资源
        objectOutputStream.close();
        
    }

}
/**
 * 这个对象会被浅拷贝和深拷贝
 * 浅拷贝:Cloneable只是起到一个标识的作用然后重写对象的克隆方法通过他调用父类构造方法
 * @author Administrator
 *
 */
class Person implements Cloneable,Serializable{

    private static final long serialVersionUID = 1L;
    String id;
    String name;
    Address address;
    
    public Person(String id,String name,Address address){
        this.id=id;
        this.name=name;
        this.address=address;
        System.out.println("=======构造方法调用了===");
    }
    @Override
    public String toString() {
        return "编号:"+ this.id+" 姓名:"+ this.name+" 地址:"+ address.city;
    }
    @Override
    public Person clone() throws CloneNotSupportedException{
        return (Person)super.clone();    
        
    }
    
}
/**
 * Person类成员类对象
 * 为了深拷贝需要为其加上Serializable
 * @author Administrator
 *
 */
class Address implements Serializable{

    private static final long serialVersionUID = 1L;
    String city;
    
    public Address(String city){
        this.city = city;
    }
    
}
View Code

3.内存管理

  java具备自动的垃圾回收机制,当我们使用完对象就会自动回收,是不是意味着我们在java程序中就不需要考虑内存管理

这个例子出栈后的对象不会被垃圾回收,依然由栈维护,最终导致内存增加就是内存泄漏

技术分享
class Stack {
    private Object[] elements;
    // 初始化角标
    int index = 0;
    // 默认初始化容量
    private int initialCapacity = 10;

    public Stack() {
        elements = new Object[initialCapacity];
    }

    // 压栈 push
    public void push(Object e) {
        ensureCapacity();
        elements[index++] = e;
        // System.out.println(index);
    }

    // 弹栈 pop
    public Object pop() {
        if (index == 0) {
            throw new RuntimeException("没有元素");
        }
        return elements[--index];
    }

    private void ensureCapacity() {
        if (index == elements.length) {
            elements = Arrays.copyOf(elements, index * 2 + 1);
        }
    }
}
View Code
这个例子对上一个改进了出栈,使其不会有内存泄漏,所以由此可见我们依然需要关注内存管理
技术分享
class Stack {
    private Object[] elements;
    // 初始化角标
    int index = 0;
    // 默认初始化容量
    private int initialCapacity = 10;

    public Stack() {
        elements = new Object[initialCapacity];
    }

    // 压栈 push
    public void push(Object e) {
        ensureCapacity();
        elements[index++] = e;
        // System.out.println(index);
    }

    // 弹栈 pop
    public Object pop() {
        if (index == 0) {
            throw new RuntimeException("没有元素");
        }
        Object obj = elements[--index];
        elements[index] = null;
        return obj;
    }

    private void ensureCapacity() {
        if (index == elements.length) {
            elements = Arrays.copyOf(elements, index * 2 + 1);
        }
    }
}
View Code

4.设计模式Design pattern

  一:观察者模式

    (一)分为观察者被观察者其中被观察者发生变化,观察着就是会做出相应的回应

    (二):原理

      观察者思路:当被观察者变化->触发观察者动作(各个观察者不同动作,所以这个动作是接口一个特定的功能)->想到这里用接口作为我们的观察者之后再具体实现他
    (三):注意:

      1.被观察者与观察者建立联系:addListener()添加监听对象
      2.被观察者发生变成触发观察者特定行为:特定行为就是接口,观察者就是接口实现对象
       3.接口实现的对象,用接口来代表观察者对象是花龙点睛之笔

    (四):例子

      这里做的例子是天气站发布天气情况发生变化收听的观察者就会做出相应的反应

      分析:需要观察者对象,被观察者对象,被观察者对象需要实现一个特定接口(这个接口作用是被观察者发生变化时触发观察者做出反应的行为)

被观察者类

技术分享
/**
 * 观察者模式
 * 被观察者,一发生变化观察着就是会做出相应的回应
 * 这里做的例子是天气站发布天气情况发生变化收听的观察者就会做出相应的反应
 * 
 * 观察者思路:当被观察者变化->触发观察者动作(各个观察者不同动作,所以这个动作是接口一个特定的功能)->想到这里用接口作为我们的观察者之后再具体实现他
 * 注意:1.被观察者与观察者建立联系:addListener()添加监听对象
 *        2.被观察者发生变成触发观察者特定行为:特定行为就是接口,观察者就是接口实现对象
 *        3.接口实现的对象,用接口来代表观察者对象是花龙点睛之笔
 * 
 * @author Administrator
 *
 */
public class WeatherStation {
    String[] weathers={"晴天","雾霾","刮风","冰雹","下雪"};
    String weather;
    //存放观察者
    ArrayList<WeatherAction> list=new ArrayList<WeatherAction>();
    
    //为其添加观察者(这一步也是必须的这是与观察 者建立联系)
    //这里能添加多个对象,我们的变化方法就需要时线程
    public void addListener(WeatherAction e){
        list.add(e);
    }
    //最主要的被观察的行为开始工作
    //将这个工作站定义为线程类型的
    public void startWork(){
        final Random random=new Random();//随机产生天气
        
        new Thread(){
            @Override
            public void run(){
                while(true){
                    updateWeather();//随机生成天气
                    for(WeatherAction e:list){//用Weather当作观察者考虑到了多态思想
                        e.notifyWeather(weather);//天气变化一次就通知一次观察者(观察者模式核心)                
                    }
                    //每次产生一个天气就休息一段时间
                    int s=random.nextInt(501)+1000;
                    try {
                        Thread.sleep(s);
                    } catch (InterruptedException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                    
                }
            }
        }.start();
    }
    //随机生成天气
    public void updateWeather() {
        Random random=new Random();
        int a=random.nextInt(weathers.length);
        weather=weathers[a];
        System.out.println("当前的天气是: " + weather);
    }
}
View Code

需要实现的接口

技术分享
/**
 * 实现这个接口的对象就是我们的观察者
 * 因为观察者对不同的被观察者结果做出不同的反应就需要通过实现这个接口来达到
 * @author Administrator
 *
 */
public interface WeatherAction {
    public void notifyWeather(String weather);
}
View Code

观察者类

技术分享
/**
 * 观察者
 * 观察者要实现触发回应的接口
 * @author Administrator
 *
 */
public class Student implements WeatherAction  {

    String name;
    public Student(String name){
        this.name=name;
    }
    @Override
    public String toString(){
        return "学生名字:"+name;
        
    }
    @Override
    public void notifyWeather(String weather) {
        if("晴天".equals(weather)){
            System.out.println(name+"高高兴兴的去开学!!");
        }else if("雾霾".equals(weather)){
            System.out.println(name+"吸多两口去上学!");
        }else if("刮风".equals(weather)){
            System.out.println(name+"在家睡觉!");
        }else if("冰雹".equals(weather)){
            System.out.println(name+"在家睡觉!");
        }else if("下雪".equals(weather)){
            System.out.println(name+"等下完再去上学!");
        }
    }
    
}
View Code
技术分享
/**
 * 观察者
 * 观察者要实现触发回应的接口
 * @author Administrator
 *
 */
public class Emp implements WeatherAction  {

    String name;
    public Emp(String name){
        this.name=name;
    }
    @Override
    public String toString(){
        return "工人名字:"+name;
        
    }
    @Override
    public void notifyWeather(String weather) {
        if("晴天".equals(weather)){
            System.out.println(name+"高高兴兴的去上班!!");
        }else if("雾霾".equals(weather)){
            System.out.println(name+"戴着消毒面具去上班!");
        }else if("刮风".equals(weather)){
            System.out.println(name+"拖着大石头过来上班!");
        }else if("冰雹".equals(weather)){
            System.out.println(name+"戴着头盔过来上班!");
        }else if("下雪".equals(weather)){
            System.out.println(name+"戴着被子过来上班!");
        }
    }
    
}
View Code

主方法

技术分享
/**
 * 观察者模式主函数
 * 接口也可以是父类
 * @author Administrator
 *
 */
public class WeatherMain {

    public static void main(String[] args) {
        Student student=new Student("小明");
        Emp emp=new Emp("老王");
        WeatherStation ws=new WeatherStation();
        ws.addListener(emp);
        ws.addListener(student);//将实现WeatherAction接口的对象作为参数
        ws.startWork();
    }

}
View Code

  二:单列模式

    (一):一个类采用Singleton模式,在这个类被创建后只能产生一个实例供外部访问,并且提供一个全局的访问点

    (二):制作单例模式类步骤

        a.定义一个私有的构造方法:防止外部调用创建了非单一实例;

        b.在类部就产生一个类的实例化对象并且用private static修饰:不能让外部直接访问到这个实例化对象,并且这个实例化对象是静态属于资源共享的

        c.定义一个静态方法返回类的实例:静态方法方便直接通过未实例化类放回内部以创建好的实例化类

    (三)分类

        a.饿汉式:线程安全但效率低 

              不存在多线程同步的问题,因为实例化对象用final来修饰

              缺点是:这个类被加载后,会初始化static的instance,被创建并分配空间,以后就一直站着这个内存,因此在某些特定条件下会耗费内存。 

技术分享
/** 
 * 方法一
 * 单例模式的实现:饿汉式,线程安全 但效率比较低 
 */  
public class SingletonTest {  

    // 定义一个私有的构造方法
    private SingletonTest() {  
    }  

    // 将自身的实例对象设置为一个属性,并加上Static和final修饰符
    private static final SingletonTest instance = new SingletonTest();  

    // 静态方法返回该类的实例
    public static SingletonTest getInstancei() {  
        return instance;  
    }  
  
}
View Code

        b.饱汉式:非线性安全

              特定条件下节省内存空间

              并发条件下可能会出现多个实例因为多线程存在线程安全-》解决办法在创建实例的方法上加上synchronized修饰这就是饱汉式升级版,线程安全 

技术分享
/**  
 *方法二
 * 单例模式的实现:饱汉式,非线程安全   
 *   
 */  
public class SingletonTest {

    // 定义私有构造方法(防止通过 new SingletonTest()去实例化)
    private SingletonTest() {   
    }   

    // 定义一个SingletonTest类型的变量(不初始化,注意这里没有使用final关键字)
    private static SingletonTest instance;   

    // 定义一个静态的方法(调用时再初始化SingletonTest,但是多线程访问时,可能造成重复初始化问题)
    public static SingletonTest getInstance() {   
        if (instance == null)   
            instance = new SingletonTest();   
        return instance;   
    }   
} 
View Code

 

        c.饱汉式:线性安全,效率变低

              特定条件下节省内存空间,并发条件下不会出现多个实例因为在创建实例的方法上加上synchronized修饰

              同步方法频繁调用时,效率略低。

技术分享
/**  
 *方法三
 * 单例模式的实现:饱汉式,线程安全简单实现   
 *   
 */  
public class SingletonTest {

    // 定义私有构造方法(防止通过 new SingletonTest()去实例化)
    private SingletonTest() {   
    }   

    // 定义一个SingletonTest类型的变量(不初始化,注意这里没有使用final关键字)
    private static SingletonTest instance;   

    // 定义一个静态的方法(调用时再初始化SingletonTest,使用synchronized 避免多线程访问时,可能造成重的复初始化问题)
    public static synchronized  SingletonTest getInstance() {   
        if (instance == null)   
            instance = new SingletonTest();   
        return instance;   
    }   
}
View Code

        d.最优方案:线程安全,效率高

              主要就是:在定义实例化对象时,用volatile 修饰,之后在创建实例化对象的静态方法上就没有加synchronized修饰

                  volatile作用:保证了多线程访问时instance变量的可见性,避免了instance初始化时其他变量属性还没赋值完时,被另外线程调用     

技术分享
/**  
 * 方法四
 * 单例模式最优方案
 * 线程安全  并且效率高  
 *  
 */  
public class SingletonTest { 

    // 定义一个私有构造方法
    private SingletonTest() { 
     
    }   
    //定义一个静态私有变量(不初始化,不使用final关键字,使用volatile保证了多线程访问时instance变量的可见性,避免了instance初始化时其他变量属性还没赋值完时,被另外线程调用)
    private static volatile SingletonTest instance;  

    //定义一个共有的静态方法,返回该类型实例
    public static SingletonTest getIstance() { 
        // 对象实例化时与否判断(不使用同步代码块,instance不等于null时,直接返回对象,提高运行效率)
        if (instance == null) {
            //同步代码块(对象未初始化时,使用同步代码块,保证多线程访问时对象在第一次创建后,不再重复被创建)
            synchronized (SingletonTest.class) {
                //未初始化,则初始instance变量
                if (instance == null) {
                    instance = new SingletonTest();   
                }   
            }   
        }   
        return instance;   
    }   
}
View Code

  三:工厂模式:就是创建对象的

例子:

技术分享
/*
工厂设计模式就是用于产生对象 的。
*/
class Car{}

class BMW extends Car{}

class BSJ extends Car{}



public class Demo1 {

    public static void main(String[] args) throws Exception {
        Person p = (Person) getInstance();
        System.out.println(p);
    }
    
    //需求: 编写一个工厂方法根据配置文件返回对应的对象。
    public static Object getInstance() throws Exception{
        //读取配置文件
        BufferedReader bufferedReader = new BufferedReader(new FileReader("info.txt"));
        //读取第一行 : 读取类文件的信息
        String className = bufferedReader.readLine();
        //通过完整类名获取对应 的Class对象
        Class clazz = Class.forName(className);
        //获取到对应的构造方法
        Constructor constructor = clazz.getDeclaredConstructor(null);
        constructor.setAccessible(true);
        Object o  = constructor.newInstance(null);
        //给对象设置对应的属性值
        String line = null;
        while((line = bufferedReader.readLine())!=null){
            String[] datas = line.split("=");
            Field field =clazz.getDeclaredField(datas[0]);
            //设置可以访问
            field.setAccessible(true);
            if(field.getType()==int.class){
                field.set(o, Integer.parseInt(datas[1]));
            }else{
                field.set(o, datas[1]);
            }
        }
        return o;
        
    }
    
    
}
View Code

其中的配置文件info.txt

FanShe.Person
id=110
name=旺财

 

        

5.反射

  一:原理由来

    类是以字节码形式存在硬盘中,当第一次new一个对象的时候,信息都被放在内存中去了,这些信息可以被访问,java中”万物皆对象“ ,这些信息也都被封装为对象

    Class类,Filed类,Method类,只通过他们就调用对象中的方法的方法叫做反射:简单来说就是访问内存中的数据

  二:获取类的字节码方式三种情况三种获取方式:forName,class,getClass()

    (一)Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");知道名字获取类的字节码

    (二)Class clazz2 = Person.class;//类获取字节码

    (三)Person p1 = new Person();Class clazz3 = p1.getClass();//实例化对象获取类字节码

  三:使用:

     a.可以通过信息对象的Class,Method,Filed类获取所需信息

      m.setAccessible(true);//设置对象的可访问

      m.invoke(p,new int[]{12,5,9});//使用反射出来的方法

被测试的类Person

技术分享
package FanShe;
/**
 * 用来测试利用反射来访问的对象
 * @author Administrator
 *
 */
public class Person {
    
    private int id;
    
    String name;
    
    public Person(int id,String name){
        this.id = id;
        this.name = name;
    }
    
    public Person(){}
    
    
    public void eat(int num){
        System.out.println(name+"吃很"+num+"斤饭");
    }
    
    @SuppressWarnings("unused")
    private static void sleep(int num){
        System.out.println("明天睡上"+num+"小时");
    }
    
    
    public static void  sum(int[] arr){
        System.out.println("长度是:"+ arr.length);
    }
    
    
    @Override
    public String toString() {
        return " 编号:"+ this.id +" 姓名:"+ this.name;
    }
    
}
View Code

获取类字节码三种方式

技术分享
package FanShe;
/**
 * 三种获取字节码方式
 * @author Administrator
 *
 */
public class Demo1 {
Person p;
    
    public static void main(String[] args) throws ClassNotFoundException {
        //Person p = new Person(110,"狗娃");
        
        //推荐使用: 获取Class对象的方式一
        Class<?> clazz1 = Class.forName("FanShe.Person");
        System.out.println("clazz1:"+ clazz1);
        
        
        //获取Class对象的方式二: 通过类名获取
        Class<?> clazz2 = Person.class;
        System.out.println("clazz1==clazz2?"+ (clazz1==clazz2));
        
        
        //获取Class对象的方式三 :通过对象获取
        Class<?> clazz3 = new Person(110,"狗娃").getClass();
        System.out.println("clazz2==clazz3?"+ (clazz2==clazz3));
        
    }
}
View Code

获取构造方法

技术分享
package FanShe;

import java.lang.reflect.Constructor;

/**
 * 通过反射来获取一些信息
 * 类的构造方法,
 * @author Administrator
 *
 */
public class Demo2 {

    public static void main(String[] args) throws Exception{
        // TODO Auto-generated method stub
        Class<?> clazz1 = Class.forName("FanShe.Person");
        //clazz1.getConstructor();//getConstructors()获取一个类的所有公共的构造方法
        //clazz1.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内
        //clazz1.getConstructor(int.class,String.class);  // getConstructor 获取单个指定的构造方法。
        
        //获取私有的构造函数
        Constructor<?> constructor =  clazz1.getDeclaredConstructor(null);
        //暴力反射
        constructor.setAccessible(true);
        Person p  =(Person) constructor.newInstance(null);
        System.out.println(p);
    }

}
View Code

获取成员方法并使用

技术分享
package FanShe;

import java.lang.reflect.Method;

public class Demo3 {

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        //获取到对应的Class对象
        Class<?> clazz = Class.forName("FanShe.Person");
        //获取到所有公共的方法
        /*Method[] methods = clazz.getMethods(); // getMethods() 获取所有 的公共方法而已。
        Method[] methods = clazz.getDeclaredMethods(); //获取到所有的方法,但是不包含父类的方法。
        for(Method method  : methods){
            System.out.println(method);
        }*/
        
        Person p = new Person(110,"狗娃");
        /*    
        Method m = clazz.getMethod("eat", int.class);
        m.invoke(p, 3); //invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。
        
        
        //执行私有的方法
        Method m =clazz.getDeclaredMethod("sleep",int.class);
        //设置访问权限允许访问
        m.setAccessible(true);
        m.invoke(null, 6);*/
        
        Method m = clazz.getMethod("sum", int[].class);
        m.invoke(p,new int[]{12,5,9});
        
    }


}
View Code

获取成员变量并使用

技术分享
package FanShe;

import java.lang.reflect.Field;

public class Demo4 {

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        //获取到对应的Class对象
        Class<?> clazz = Class.forName("FanShe.Person");
        //获取 到所有的成员变量
        /*Field[] fields = clazz.getDeclaredFields();
        for(Field field  : fields){
            System.out.println(field);
        }*/
        Person p = new Person();
        Field field = clazz.getDeclaredField("id");
        //设置访问权限可以访问
        field.setAccessible(true);
        field.set(p, 110); //第一个参数: 设置该数据 的成员变量, 第二个参数:属性值。
        System.out.println(p);
    }

}
View Code

 

java入门了解15