信息发布软件,b2b软件,广告发布软件

 找回密码
 立即注册
搜索
查看: 1703|回复: 2
打印 上一主题 下一主题

[『 Java 图文教程』] JAVA中浅复制与深复制和多方法实例教程

  [复制链接]

587

主题

671

帖子

4360

积分

积分
4360
跳转到指定楼层
宣传软件楼主
发表于 2016-10-17 11:06:47 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

软件教程首图:

软件教程分类:Java 图文教程 

软件图文教程视频教程分类:软件图文教程 

软件教程难易程度:软件初级教程 

软件教程发布日期:2016-10-17

软件教程关键字:JAVA中浅复制与深复制

① 本信息收集于网络,如有不对的地方欢迎联系我纠正!
② 本信息免费收录,不存在价格的问题!
③ 如果您的网站也想这样出现在这里,请您加好友情链接,我当天会审核通过!

④友情链接关键字:软件定制网站 网址:http://www.postbbs.com

软件教程详细描述
本帖最后由 信息发布软件 于 2016-10-17 11:09 编辑

 1.浅复制与深复制概念

⑴浅复制(浅克隆)

被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。


⑵深复制(深克隆)

被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。


  2.Java的clone()方法

⑴clone方法将对象复制了一份并返回给调用者。一般而言,clone()方法满足:

①对任何的对象x,都有x.clone() !=x//克隆对象与原对象不是同一个对象

②对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样

③如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。


⑵Java中对象的克隆

①为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。

②在派生类中覆盖基类的clone()方法,并声明为public。

③在派生类的clone()方法中,调用super.clone()。

④在派生类中实现Cloneable接口。


请看如下代码:


class Student implements Cloneable

{

String name;

int age;

Student(String name,int age)

{

this.name=name;

this.age=age;

}

public Object clone()

{

Object o=null;

try

{

o=(Student)super.clone();//Object中的clone()识别出你要复制的是哪一

// 个对象。

}


catch(CloneNotSupportedException e)

{

System.out.println(e.toString());

}

return o;

}

}


public static void main(String[] args)

{

Student s1=new Student("zhangsan",18);

Student s2=(Student)s1.clone();

s2.name="lisi";

s2.age=20;

System.out.println("name="+s1.name+","+"age="+s1.age);//修改学生2后,不影响

//学生1的值。

}


说明:

①为什么我们在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?在运行时刻,Object中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。

②继承自java.lang.Object类的clone()方法是浅复制。以下代码可以证明之。


class Professor

{

String name;

int age;

Professor(String name,int age)

{

this.name=name;

this.age=age;

}

}

class Student implements Cloneable

{

String name;//常量对象。

int age;

Professor p;//学生1和学生2的引用值都是一样的。

Student(String name,int age,Professor p)

{

this.name=name;

this.age=age;

this.p=p;

}

public Object clone()

{

Student o=null;

try

{

o=(Student)super.clone();

}


catch(CloneNotSupportedException e)

{

System.out.println(e.toString());

}

o.p=(Professor)p.clone();

return o;

}

}

public static void main(String[] args)

{

Professor p=new Professor("wangwu",50);

Student s1=new Student("zhangsan",18,p);

Student s2=(Student)s1.clone();

s2.p.name="lisi";

s2.p.age=30;

System.out.println("name="+s1.p.name+","+"age="+s1.p.age);//学生1的教授

//成为lisi,age为30。

}

  那应该如何实现深层次的克隆,即修改s2的教授不会影响s1的教授?代码改进如下。


改进使学生1的Professor不改变(深层次的克隆)

class Professor implements Cloneable

{

String name;

int age;

Professor(String name,int age)

{

this.name=name;

this.age=age;

}

public Object clone()

{

Object o=null;

try

{

o=super.clone();

}

catch(CloneNotSupportedException e)

{

System.out.println(e.toString());

}

return o;

}

}

class Student implements Cloneable

{

String name;

int age;

Professor p;

Student(String name,int age,Professor p)

{

this.name=name;

this.age=age;

this.p=p;

}


public Object clone()

{

Student o=null;

try

{

o=(Student)super.clone();

}

catch(CloneNotSupportedException e)

{

System.out.println(e.toString());

}

o.p=(Professor)p.clone();

return o;

}

}

public static void main(String[] args)

{

Professor p=new Professor("wangwu",50);

Student s1=new Student("zhangsan",18,p);

Student s2=(Student)s1.clone();

s2.p.name="lisi";

s2.p.age=30;

System.out.println("name="+s1.p.name+","+"age="+s1.p.age);//学生1的教授不改变。

}


  3.利用串行化来做深复制

把对象写到流里的过程是串行化(Serilization)过程,但是在Java程序师圈子里又非常形象地称为“冷冻”或者“腌咸菜(picking)”过程;而把对象从流中读出来的并行化(Deserialization)过程则叫做“解冻”或者“回鲜(depicking)”过程。应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面,因此“腌成咸菜”的只是对象的一个拷贝,Java咸菜还可以回鲜。

在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里(腌成咸菜),再从流里读出来(把咸菜回鲜),便可以重建对象。

如下为深复制源代码。

public Object deepClone()

{

//将对象写到流里

ByteArrayOutoutStream bo=new ByteArrayOutputStream();

ObjectOutputStream oo=new ObjectOutputStream(bo);

oo.writeObject(this);

//从流里读出来

ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());

ObjectInputStream oi=new ObjectInputStream(bi);

return(oi.readObject());

}


这样做的前提是对象以及对象内部所有引用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象可否设成transient,从而将之排除在复制过程之外。上例代码改进如下。


class Professor implements Serializable

{

String name;

int age;

Professor(String name,int age)

{

this.name=name;

this.age=age;

}


}

class Student implements Serializable

{

String name;//常量对象。

int age;

Professor p;//学生1和学生2的引用值都是一样的。

Student(String name,int age,Professor p)

{

this.name=name;

this.age=age;

this.p=p;

}

public Object deepClone() throws IOException,

OptionalDataException,ClassNotFoundException

{

//将对象写到流里

ByteArrayOutoutStream bo=new ByteArrayOutputStream();

ObjectOutputStream oo=new ObjectOutputStream(bo);

oo.writeObject(this);

//从流里读出来

ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());

ObjectInputStream oi=new ObjectInputStream(bi);

return(oi.readObject());

}


}

public static void main(String[] args)

{

Professor p=new Professor("wangwu",50);

Student s1=new Student("zhangsan",18,p);

Student s2=(Student)s1.deepClone();

s2.p.name="lisi";

s2.p.age=30;

System.out.println("name="+s1.p.name+","+"age="+s1.p.age); //学生1的教授不改变。

}



untoJava对象的强、软、弱和虚引用和多方法实例教程next深入Java对象及元素的存储区域和实例教程
回复

使用道具 举报

587

主题

671

帖子

4360

积分

积分
4360
信息发布软件沙发
 楼主| 发表于 2016-10-17 11:11:26 | 只看该作者
实例方法2

假如说你想复制一个简单变量。很简单:

  • int apples = 5;
  • int pears = apples;

                int apples = 5;                int pears = apples;
不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float,double.long)同样适用于该类情况。

但是如果你复制的是一个对象,情况就有些复杂了。

假设说我是一个beginner,我会这样写:

  • class Student {
  •     private int number;
  •     public int getNumber() {
  •         return number;
  •     }
  •     public void setNumber(int number) {
  •         this.number = number;
  •     }
  • }
  • public class Test {
  •     public static void main(String args[]) {
  •         Student stu1 = new Student();
  •         stu1.setNumber(12345);
  •         Student stu2 = stu1;
  •         System.out.println("学生1:" + stu1.getNumber());
  •         System.out.println("学生2:" + stu2.getNumber());
  •     }
  • }

class Student {        private int number;        public int getNumber() {                return number;        }        public void setNumber(int number) {                this.number = number;        }        }public class Test {                public static void main(String args[]) {                                Student stu1 = new Student();                stu1.setNumber(12345);                Student stu2 = stu1;                                System.out.println("学生1:" + stu1.getNumber());                System.out.println("学生2:" + stu2.getNumber());        }}

打印结果:

  • 学生1:12345
  • 学生2:12345

学生1:12345学生2:12345
这里我们自定义了一个学生类,该类只有一个number字段。
我们新建了一个学生实例,然后将该值赋值给stu2实例。(Student stu2 = stu1;)
再看看打印结果,作为一个新手,拍了拍胸腹,对象复制不过如此,
难道真的是这样吗?

我们试着改变stu2实例的number字段,再打印结果看看:

  • stu2.setNumber(54321);
  • System.out.println("学生1:" + stu1.getNumber());
  • System.out.println("学生2:" + stu2.getNumber());

                stu2.setNumber(54321);                        System.out.println("学生1:" + stu1.getNumber());                System.out.println("学生2:" + stu2.getNumber());
打印结果:


  • 学生1:54321
  • 学生2:54321

学生1:54321学生2:54321
这就怪了,为什么改变学生2的学号,学生1的学号也发生了变化呢?


原因出在(stu2 = stu1) 这一句。该语句的作用是将stu1的引用赋值给stu2,
这样,stu1和stu2指向内存堆中同一个对象。如图:
JAVA中浅复制与深复制和多方法实例教程 b2b软件

那么,怎样才能达到复制一个对象呢?
是否记得万类之王Object。它有11个方法,有两个protected的方法,其中一个为clone方法。
该方法的签名是:
protected native Object clone() throws CloneNotSupportedException;

因为每个类直接或间接的父类都是Object,因此它们都含有clone()方法,但是因为该方法是protected,所以都不能在类外进行访问。
要想对一个对象进行复制,就需要对clone方法覆盖。

一般步骤是(浅复制):
1. 被复制的类需要实现Clonenable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常) 该接口为标记接口(不含任何方法)
2. 覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象,(native为本地方法)

下面对上面那个方法进行改造:

  • class Student implements Cloneable{
  •     private int number;
  •     public int getNumber() {
  •         return number;
  •     }
  •     public void setNumber(int number) {
  •         this.number = number;
  •     }
  •     @Override
  •     public Object clone() {
  •         Student stu = null;
  •         try{
  •             stu = (Student)super.clone();
  •         }catch(CloneNotSupportedException e) {
  •             e.printStackTrace();
  •         }
  •         return stu;
  •     }
  • }
  • public class Test {
  •     public static void main(String args[]) {
  •         Student stu1 = new Student();
  •         stu1.setNumber(12345);
  •         Student stu2 = (Student)stu1.clone();
  •         System.out.println("学生1:" + stu1.getNumber());
  •         System.out.println("学生2:" + stu2.getNumber());
  •         stu2.setNumber(54321);
  •         System.out.println("学生1:" + stu1.getNumber());
  •         System.out.println("学生2:" + stu2.getNumber());
  •     }
  • }

class Student implements Cloneable{        private int number;        public int getNumber() {                return number;        }        public void setNumber(int number) {                this.number = number;        }                @Override        public Object clone() {                Student stu = null;                try{                        stu = (Student)super.clone();                }catch(CloneNotSupportedException e) {                        e.printStackTrace();                }                return stu;        }}public class Test {                public static void main(String args[]) {                                Student stu1 = new Student();                stu1.setNumber(12345);                Student stu2 = (Student)stu1.clone();                                System.out.println("学生1:" + stu1.getNumber());                System.out.println("学生2:" + stu2.getNumber());                                stu2.setNumber(54321);                        System.out.println("学生1:" + stu1.getNumber());                System.out.println("学生2:" + stu2.getNumber());        }}
打印结果:


  • 学生1:12345
  • 学生2:12345
  • 学生1:12345
  • 学生2:54321

学生1:12345学生2:12345学生1:12345学生2:54321
如果你还不相信这两个对象不是同一个对象,那么你可以看看这一句:


  • System.out.println(stu1 == stu2); // false

                System.out.println(stu1 == stu2); // false
上面的复制被称为浅复制(Shallow Copy),还有一种稍微复杂的深度复制(deep copy):
我们在学生类里再加一个Address类。

  • class Address  {
  •     private String add;
  •     public String getAdd() {
  •         return add;
  •     }
  •     public void setAdd(String add) {
  •         this.add = add;
  •     }
  • }
  • class Student implements Cloneable{
  •     private int number;
  •     private Address addr;
  •     public Address getAddr() {
  •         return addr;
  •     }
  •     public void setAddr(Address addr) {
  •         this.addr = addr;
  •     }
  •     public int getNumber() {
  •         return number;
  •     }
  •     public void setNumber(int number) {
  •         this.number = number;
  •     }
  •     @Override
  •     public Object clone() {
  •         Student stu = null;
  •         try{
  •             stu = (Student)super.clone();
  •         }catch(CloneNotSupportedException e) {
  •             e.printStackTrace();
  •         }
  •         return stu;
  •     }
  • }
  • public class Test {
  •     public static void main(String args[]) {
  •         Address addr = new Address();
  •         addr.setAdd("杭州市");
  •         Student stu1 = new Student();
  •         stu1.setNumber(123);
  •         stu1.setAddr(addr);
  •         Student stu2 = (Student)stu1.clone();
  •         System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
  •         System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
  •     }
  • }

class Address  {        private String add;        public String getAdd() {                return add;        }        public void setAdd(String add) {                this.add = add;        }        }class Student implements Cloneable{        private int number;        private Address addr;                public Address getAddr() {                return addr;        }        public void setAddr(Address addr) {                this.addr = addr;        }        public int getNumber() {                return number;        }        public void setNumber(int number) {                this.number = number;        }                @Override        public Object clone() {                Student stu = null;                try{                        stu = (Student)super.clone();                }catch(CloneNotSupportedException e) {                        e.printStackTrace();                }                return stu;        }}public class Test {                public static void main(String args[]) {                                Address addr = new Address();                addr.setAdd("杭州市");                Student stu1 = new Student();                stu1.setNumber(123);                stu1.setAddr(addr);                                Student stu2 = (Student)stu1.clone();                                System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());                System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());        }}
打印结果:


  • 学生1:123,地址:杭州市
  • 学生2:123,地址:杭州市

学生1:123,地址:杭州市学生2:123,地址:杭州市
乍一看没什么问题,真的是这样吗?

我们在main方法中试着改变addr实例的地址。

  • addr.setAdd("西湖区");
  • System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
  • System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());

                addr.setAdd("西湖区");                                System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());                System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
打印结果:


  • 学生1:123,地址:杭州市
  • 学生2:123,地址:杭州市
  • 学生1:123,地址:西湖区
  • 学生2:123,地址:西湖区

学生1:123,地址:杭州市学生2:123,地址:杭州市学生1:123,地址:西湖区学生2:123,地址:西湖区
这就奇怪了,怎么两个学生的地址都改变了?

原因是浅复制只是复制了addr变量的引用,并没有真正的开辟另一块空间,将值复制后再将引用返回给新对象。
所以,为了达到真正的复制对象,而不是纯粹引用复制。我们需要将Address类可复制化,并且修改clone方法,完整代码如下:


  • package abc;
  • class Address implements Cloneable {
  •     private String add;
  •     public String getAdd() {
  •         return add;
  •     }
  •     public void setAdd(String add) {
  •         this.add = add;
  •     }
  •     @Override
  •     public Object clone() {
  •         Address addr = null;
  •         try{
  •             addr = (Address)super.clone();
  •         }catch(CloneNotSupportedException e) {
  •             e.printStackTrace();
  •         }
  •         return addr;
  •     }
  • }
  • class Student implements Cloneable{
  •     private int number;
  •     private Address addr;
  •     public Address getAddr() {
  •         return addr;
  •     }
  •     public void setAddr(Address addr) {
  •         this.addr = addr;
  •     }
  •     public int getNumber() {
  •         return number;
  •     }
  •     public void setNumber(int number) {
  •         this.number = number;
  •     }
  •     @Override
  •     public Object clone() {
  •         Student stu = null;
  •         try{
  •             stu = (Student)super.clone();   //浅复制  
  •         }catch(CloneNotSupportedException e) {
  •             e.printStackTrace();
  •         }
  •         stu.addr = (Address)addr.clone();   //深度复制  
  •         return stu;
  •     }
  • }
  • public class Test {
  •     public static void main(String args[]) {
  •         Address addr = new Address();
  •         addr.setAdd("杭州市");
  •         Student stu1 = new Student();
  •         stu1.setNumber(123);
  •         stu1.setAddr(addr);
  •         Student stu2 = (Student)stu1.clone();
  •         System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
  •         System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
  •         addr.setAdd("西湖区");
  •         System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
  •         System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
  •     }
  • }

package abc;class Address implements Cloneable {        private String add;        public String getAdd() {                return add;        }        public void setAdd(String add) {                this.add = add;        }                @Override        public Object clone() {                Address addr = null;                try{                        addr = (Address)super.clone();                }catch(CloneNotSupportedException e) {                        e.printStackTrace();                }                return addr;        }}class Student implements Cloneable{        private int number;        private Address addr;                public Address getAddr() {                return addr;        }        public void setAddr(Address addr) {                this.addr = addr;        }        public int getNumber() {                return number;        }        public void setNumber(int number) {                this.number = number;        }                @Override        public Object clone() {                Student stu = null;                try{                        stu = (Student)super.clone();        //浅复制                }catch(CloneNotSupportedException e) {                        e.printStackTrace();                }                stu.addr = (Address)addr.clone();        //深度复制                return stu;        }}public class Test {                public static void main(String args[]) {                                Address addr = new Address();                addr.setAdd("杭州市");                Student stu1 = new Student();                stu1.setNumber(123);                stu1.setAddr(addr);                                Student stu2 = (Student)stu1.clone();                                System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());                System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());                                addr.setAdd("西湖区");                                System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());                System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());        }}
打印结果:


  • 学生1:123,地址:杭州市
  • 学生2:123,地址:杭州市
  • 学生1:123,地址:西湖区
  • 学生2:123,地址:杭州市

学生1:123,地址:杭州市学生2:123,地址:杭州市学生1:123,地址:西湖区学生2:123,地址:杭州市
这样结果就符合我们的想法了。
总结:浅拷贝是指在拷贝对象时,对于基本数据类型的变量会重新复制一份,而对于引用类型的变量只是对引用进行拷贝,
没有对引用指向的对象进行拷贝。
而深拷贝是指在拷贝对象时,同时会对引用指向的对象进行拷贝。
区别就在于是否对  对象中的引用变量所指向的对象进行拷贝。

最后我们可以看看API里其中一个实现了clone方法的类:
java.util.Date:

  • /**
  • * Return a copy of this object.
  • */
  • public Object clone() {
  •     Date d = null;
  •     try {
  •         d = (Date)super.clone();
  •         if (cdate != null) {
  •             d.cdate = (BaseCalendar.Date) cdate.clone();
  •         }
  •     } catch (CloneNotSupportedException e) {} // Won't happen  
  •     return d;
  • }

    /**     * Return a copy of this object.     */    public Object clone() {        Date d = null;        try {            d = (Date)super.clone();            if (cdate != null) {                d.cdate = (BaseCalendar.Date) cdate.clone();            }        } catch (CloneNotSupportedException e) {} // Won't happen        return d;    }
该类其实也属于深度复制。


回复 支持 反对

使用道具 举报

587

主题

671

帖子

4360

积分

积分
4360
推广工具板凳
 楼主| 发表于 2016-10-17 11:12:30 | 只看该作者
实例教程3

Java语言的一个优点就是取消了指针的概念,但也导致了许多程序员在编程中常常忽略了对象与引用的区别,本文会试图澄清这一概念。并且由于Java不能通过简单的赋值来解决对象复制的问题,在开发过程中,也常常要要应用clone()方法来复制对象。本文会让你了解什么是影子clone与深度clone,认识它们的区别、优点及缺点。
      看到这个标题,是不是有点困惑:Java语言明确说明取消了指针,因为指针往往是在带来方便的同时也是导致代码不安全的根源,同时也会使程序的变得非常复杂难以理解,滥用指针写成的代码不亚于使用早已臭名昭著的"GOTO"语句。Java放弃指针的概念绝对是极其明智的。但这只是在Java语言中没有明确的指针定义,实质上每一个new语句返回的都是一个指针的引用,只不过在大多时候Java中不用关心如何操作这个"指针",更不用象在操作C++的指针那样胆战心惊。唯一要多多关心的是在给函数传递对象的时候。

[java] view plain copy


  • package com.zoer.src;  
  •   
  • public class ObjRef {  
  •     Obj aObj = new Obj();  
  •     int aInt = 11;  
  •   
  •     public void changeObj(Obj inObj) {  
  •         inObj.str = "changed value";  
  •     }  
  •   
  •     public void changePri(int inInt) {  
  •         inInt = 22;  
  •     }  
  •   
  •     public static void main(String[] args) {  
  •         ObjRef oRef = new ObjRef();  
  •   
  •         System.out.println("Before call changeObj() method: " + oRef.aObj);  
  •         oRef.changeObj(oRef.aObj);  
  •         System.out.println("After call changeObj() method: " + oRef.aObj);  
  •   
  •         System.out.println("==================Print Primtive=================");  
  •         System.out.println("Before call changePri() method: " + oRef.aInt);  
  •         oRef.changePri(oRef.aInt);  
  •         System.out.println("After call changePri() method: " + oRef.aInt);  
  •   
  •     }  
  • }  

[java] view plain copy


  • package com.zoer.src;  
  •   
  • public class Obj {  
  •   
  •     String str = "init value";  
  •   
  •     public String toString() {  
  •         return str;  
  •     }  
  • }  

      这段代码的主要部分调用了两个很相近的方法,changeObj()和changePri()。唯一不同的是它们一个把对象作为输入参数,另一个把Java中的基本类型int作为输入参数。并且在这两个函数体内部都对输入的参数进行了改动。看似一样的方法,程序输出的结果却不太一样。changeObj()方法真正的把输入的参数改变了,而changePri()方法对输入的参数没有任何的改变。

      从这个例子知道Java对对象和基本的数据类型的处理是不一样的。和C语言一样,当把Java的基本数据类型(如int,char,double等)作为入口参数传给函数体的时候,传入的参数在函数体内部变成了局部变量,这个局部变量是输入参数的一个拷贝,所有的函数体内部的操作都是针对这个拷贝的操作,函数执行结束后,这个局部变量也就完成了它的使命,它影响不到作为输入参数的变量。这种方式的参数传递被称为"值传递"。而在Java中用对象作为入口参数的传递则缺省为"引用传递",也就是说仅仅传递了对象的一个"引用",这个"引用"的概念同C语言中的指针引用是一样的。当函数体内部对输入变量改变时,实质上就是在对这个对象的直接操作。
      除了在函数传值的时候是"引用传递",在任何用"="向对象变量赋值的时候都是"引用传递"。就是类似于给变量再起一个别名。两个名字都指向内存中的同一个对象。
      在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。在Java语言中,用简单的赋值语句是不能满足这种需求的。要满足这种需求虽然有很多途径,但实现clone()方法是其中最简单,也是最高效的手段。
      Java的所有类都默认继承java.lang.Object类,在java.lang.Object类中有一个方法clone()。JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。要说明的有两点:一是拷贝对象返回的是一个新对象,而不是一个引用。二是拷贝对象与用new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。
      怎样应用clone()方法?

      一个很典型的调用clone()代码如下:

[java] view plain copy


  • public class CloneClass implements Cloneable {  
  •     public int aInt;  
  •   
  •     public Object clone() {  
  •         CloneClass o = null;  
  •         try {  
  •             o = (CloneClass) super.clone();  
  •         } catch (CloneNotSupportedException e) {  
  •             e.printStackTrace();  
  •         }  
  •         return o;  
  •     }  
  • }  

      有三个值得注意的地方,一是希望能实现clone功能的CloneClass类实现了Cloneable接口,这个接口属于java.lang包,java.lang包已经被缺省的导入类中,所以不需要写成java.lang.Cloneable。另一个值得请注意的是重载了clone()方法。最后在clone()方法中调用了super.clone(),这也意味着无论clone类的继承结构是什么样的,super.clone()直接或间接调用了java.lang.Object类的clone()方法。下面再详细的解释一下这几点。
      应该说第三点是最重要的,仔细观察一下Object类的clone()一个native方法,native方法的效率一般来说都是远高于java中的非native方法。这也解释了为什么要用Object中clone()方法而不是先new一个类,然后把原始对象中的信息赋到新对象中,虽然这也实现了clone功能。对于第二点,也要观察Object类中的clone()还是一个protected属性的方法。这也意味着如果要应用clone()方法,必须继承Object类,在Java中所有的类是缺省继承Object类的,也就不用关心这点了。然后重载clone()方法。还有一点要考虑的是为了让其它类能调用这个clone类的clone()方法,重载之后要把clone()方法的属性设置为public。
       那么clone类为什么还要实现Cloneable接口呢?稍微注意一下,Cloneable接口是不包含任何方法的!其实这个接口仅仅是一个标志,而且这个标志也仅仅是针对Object类中clone()方法的,如果clone类没有实现Cloneable接口,并调用了Object的clone()方法(也就是调用了super.Clone()方法),那么Object的clone()方法就会抛出CloneNotSupportedException异常。
      以上是clone的最基本的步骤,想要完成一个成功的clone,还要了解什么是"影子clone"和"深度clone"。
      什么是影子clone?

[java] view plain copy


  • package com.zoer.src;  
  •   
  • class UnCloneA {  
  •     private int i;  
  •   
  •     public UnCloneA(int ii) {  
  •         i = ii;  
  •     }  
  •   
  •     public void doublevalue() {  
  •         i *= 2;  
  •     }  
  •   
  •     public String toString() {  
  •         return Integer.toString(i);  
  •     }  
  • }  
  •   
  • class CloneB implements Cloneable {  
  •     public int aInt;  
  •     public UnCloneA unCA = new UnCloneA(111);  
  •   
  •     public Object clone() {  
  •         CloneB o = null;  
  •         try {  
  •             o = (CloneB) super.clone();  
  •         } catch (CloneNotSupportedException e) {  
  •             e.printStackTrace();  
  •         }  
  •         return o;  
  •     }  
  • }  
  •   
  • public class ObjRef {  
  •     public static void main(String[] a) {  
  •         CloneB b1 = new CloneB();  
  •         b1.aInt = 11;  
  •         System.out.println("before clone,b1.aInt = " + b1.aInt);  
  •         System.out.println("before clone,b1.unCA = " + b1.unCA);  
  •   
  •         CloneB b2 = (CloneB) b1.clone();  
  •         b2.aInt = 22;  
  •         b2.unCA.doublevalue();  
  •         System.out.println("=================================");  
  •         System.out.println("after clone,b1.aInt = " + b1.aInt);  
  •         System.out.println("after clone,b1.unCA = " + b1.unCA);  
  •         System.out.println("=================================");  
  •         System.out.println("after clone,b2.aInt = " + b2.aInt);  
  •         System.out.println("after clone,b2.unCA = " + b2.unCA);  
  •     }  
  • }  

       输出结果:
before clone,b1.aInt = 11
before clone,b1.unCA = 111
=================================
after clone,b1.aInt = 11
after clone,b1.unCA = 222
=================================
after clone,b2.aInt = 22
after clone,b2.unCA = 222

       输出的结果说明int类型的变量aInt和UnCloneA的实例对象unCA的clone结果不一致,int类型是真正的被clone了,因为改变了b2中的aInt变量,对b1的aInt没有产生影响,也就是说,b2.aInt与b1.aInt已经占据了不同的内存空间,b2.aInt是b1.aInt的一个真正拷贝。相反,对b2.unCA的改变同时改变了b1.unCA,很明显,b2.unCA和b1.unCA是仅仅指向同一个对象的不同引用!从中可以看出,调用Object类中clone()方法产生的效果是:先在内存中开辟一块和原始对象一样的空间,然后原样拷贝原始对象中的内容。对基本数据类型,这样的操作是没有问题的,但对非基本类型变量,我们知道它们保存的仅仅是对象的引用,这也导致clone后的非基本类型变量和原始对象中相应的变量指向的是同一个对象。
       大多时候,这种clone的结果往往不是我们所希望的结果,这种clone也被称为"影子clone"。要想让b2.unCA指向与b2.unCA不同的对象,而且b2.unCA中还要包含b1.unCA中的信息作为初始信息,就要实现深度clone。
       怎么进行深度clone?
       把上面的例子改成深度clone很简单,需要两个改变:一是让UnCloneA类也实现和CloneB类一样的clone功能(实现Cloneable接口,重载clone()方法)。二是在CloneB的clone()方法中加入一句o.unCA = (UnCloneA)unCA.clone();

[java] view plain copy


  • package com.zoer.src;  
  •   
  • class UnCloneA implements Cloneable {  
  •     private int i;  
  •   
  •     public UnCloneA(int ii) {  
  •         i = ii;  
  •     }  
  •   
  •     public void doublevalue() {  
  •         i *= 2;  
  •     }  
  •   
  •     public String toString() {  
  •         return Integer.toString(i);  
  •     }  
  •   
  •     public Object clone() {  
  •         UnCloneA o = null;  
  •         try {  
  •             o = (UnCloneA) super.clone();  
  •         } catch (CloneNotSupportedException e) {  
  •             e.printStackTrace();  
  •         }  
  •         return o;  
  •     }  
  • }  
  •   
  • class CloneB implements Cloneable {  
  •     public int aInt;  
  •     public UnCloneA unCA = new UnCloneA(111);  
  •   
  •     public Object clone() {  
  •         CloneB o = null;  
  •         try {  
  •             o = (CloneB) super.clone();  
  •         } catch (CloneNotSupportedException e) {  
  •             e.printStackTrace();  
  •         }  
  •         o.unCA = (UnCloneA) unCA.clone();  
  •         return o;  
  •     }  
  • }  
  •   
  • public class CloneMain {  
  •     public static void main(String[] a) {  
  •         CloneB b1 = new CloneB();  
  •         b1.aInt = 11;  
  •         System.out.println("before clone,b1.aInt = " + b1.aInt);  
  •         System.out.println("before clone,b1.unCA = " + b1.unCA);  
  •   
  •         CloneB b2 = (CloneB) b1.clone();  
  •         b2.aInt = 22;  
  •         b2.unCA.doublevalue();  
  •         System.out.println("=================================");  
  •         System.out.println("after clone,b1.aInt = " + b1.aInt);  
  •         System.out.println("after clone,b1.unCA = " + b1.unCA);  
  •         System.out.println("=================================");  
  •         System.out.println("after clone,b2.aInt = " + b2.aInt);  
  •         System.out.println("after clone,b2.unCA = " + b2.unCA);  
  •     }  
  • }  


输出结果:
before clone,b1.aInt = 11
before clone,b1.unCA = 111
=================================
after clone,b1.aInt = 11
after clone,b1.unCA = 111
=================================
after clone,b2.aInt = 22
after clone,b2.unCA = 222

      可以看出,现在b2.unCA的改变对b1.unCA没有产生影响。此时b1.unCA与b2.unCA指向了两个不同的UnCloneA实例,而且在CloneB b2 = (CloneB)b1.clone();调用的那一刻b1和b2拥有相同的值,在这里,b1.i = b2.i = 11。
        要知道不是所有的类都能实现深度clone的。例如,如果把上面的CloneB类中的UnCloneA类型变量改成StringBuffer类型,看一下JDK API中关于StringBuffer的说明,StringBuffer没有重载clone()方法,更为严重的是StringBuffer还是一个final类,这也是说我们也不能用继承的办法间接实现StringBuffer的clone。如果一个类中包含有StringBuffer类型对象或和StringBuffer相似类的对象,我们有两种选择:要么只能实现影子clone,要么就在类的clone()方法中加一句(假设是SringBuffer对象,而且变量名仍是unCA): o.unCA = new StringBuffer(unCA.toString()); //原来的是:o.unCA = (UnCloneA)unCA.clone();
       还要知道的是除了基本数据类型能自动实现深度clone以外,String对象是一个例外,它clone后的表现好象也实现了深度clone,虽然这只是一个假象,但却大大方便了我们的编程。
       Clone中String和StringBuffer的区别
       应该说明的是,这里不是着重说明String和StringBuffer的区别,但从这个例子里也能看出String类的一些与众不同的地方。
       下面的例子中包括两个类,CloneC类包含一个String类型变量和一个StringBuffer类型变量,并且实现了clone()方法。在StrClone类中声明了CloneC类型变量c1,然后调用c1的clone()方法生成c1的拷贝c2,在对c2中的String和StringBuffer类型变量用相应的方法改动之后打印结果:

[java] view plain copy


  • package com.zoer.src;  
  •   
  • class CloneC implements Cloneable {  
  •     public String str;  
  •     public StringBuffer strBuff;  
  •   
  •     public Object clone() {  
  •         CloneC o = null;  
  •         try {  
  •             o = (CloneC) super.clone();  
  •         } catch (CloneNotSupportedException e) {  
  •             e.printStackTrace();  
  •         }  
  •         return o;  
  •     }  
  •   
  • }  
  •   
  • public class StrClone {  
  •     public static void main(String[] a) {  
  •         CloneC c1 = new CloneC();  
  •         c1.str = new String("initializeStr");  
  •         c1.strBuff = new StringBuffer("initializeStrBuff");  
  •         System.out.println("before clone,c1.str = " + c1.str);  
  •         System.out.println("before clone,c1.strBuff = " + c1.strBuff);  
  •   
  •         CloneC c2 = (CloneC) c1.clone();  
  •         c2.str = c2.str.substring(0, 5);  
  •         c2.strBuff = c2.strBuff.append(" change strBuff clone");  
  •         System.out.println("=================================");  
  •         System.out.println("after clone,c1.str = " + c1.str);  
  •         System.out.println("after clone,c1.strBuff = " + c1.strBuff);  
  •         System.out.println("=================================");  
  •         System.out.println("after clone,c2.str = " + c2.str);  
  •         System.out.println("after clone,c2.strBuff = " + c2.strBuff);  
  •     }  
  • }  


执行结果:

[java] view plain copy


  • <span style="font-family:'Microsoft YaHei';"><span style="font-size:16px;">before clone,c1.str = initializeStr  
  • before clone,c1.strBuff = initializeStrBuff  
  • =================================  
  • after clone,c1.str = initializeStr  
  • after clone,c1.strBuff = initializeStrBuff change strBuff clone  
  • =================================  
  • after clone,c2.str = initi  
  • after clone,c2.strBuff = initializeStrBuff change strBuff clone  
  • </span></span>  


        打印的结果可以看出,String类型的变量好象已经实现了深度clone,因为对c2.str的改动并没有影响到c1.str!难道Java把Sring类看成了基本数据类型?其实不然,这里有一个小小的把戏,秘密就在于c2.str = c2.str.substring(0,5)这一语句!实质上,在clone的时候c1.str与c2.str仍然是引用,而且都指向了同一个String对象。但在执行c2.str = c2.str.substring(0,5)的时候,它作用相当于生成了一个新的String类型,然后又赋回给c2.str。这是因为String被Sun公司的工程师写成了一个不可更改的类(immutable class),在所有String类中的函数都不能更改自身的值。


回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

相关导读
群发软件AIWROK软件如何训练自己的数据集
通用yolo模型aiwork平台提供了通用yolov5插件,可以自行下载开源训练库或者把你已经训练好的yolov5模型转成.tflite格式即可使用调用案例:复制var yolo=new yoloV5(); //可以自己配置是否gpu加速和int8量化 yolo.loadTFMode("/插件/fp16_320.tflite","/插件/YoloV5.txt",320,false,false,false); //或者简写 //yolo.loadTFMode("/插件/fp16_320.tflite","/插件/YoloV5.txt",640); //本地图片识别 var img=new image().readT
群发软件AIWROK常用的随机位置范围点击随机拖动
/* * 随机位置点击函数 * @param {number} x - 点击位置的百分比 X 坐标 * @param {number} y - 点击位置的百分比 Y 坐标 * @param {number} x范围 - X 坐标的随机范围 * @param {number} y范围 - Y 坐标的随机范围 */function 随机位置点击(x, y, x范围, y范围) { // 将百分比坐标转成真实坐标 var x1 = screen.percentToWidth(x); var y1 = screen.percentToHeight(y); // 在指定范围内生成新的随机坐标 x1 = ran
群发软件AIWROK软件FTP完整例子自动链接可以上传可以下载
AIWROK软件FTP完整例子自动链接可以上传可以下载/* 欢迎使用AiWork安卓自动化IDE qq群: 711841924 */// 加载FTP库rhino.loadDex(project.getResourcesPath() + "ftp.dex");importClass(org.apache.commons.net.ftp.FTP);importClass(org.apache.commons.net.ftp.FTPClient);importPackage(java.io);// FTP配置参数var ftpHost = "154.201.80.249";var ftpPort = 21;var username = "rtyerye";var password = "8AafKDs4KhMDR3yy
群发软件AIWROK真正能包打天下的三种查找随机方法
AIWROK真正能包打天下的三种查找随机方法// 图片文字识别相关方法// 使用opencv的OCR进行文字识别并随机点击function 找字随机点击() { var ocr = opencv.OCREx('今日头条极速版8.cv'); if(!ocr) return; var target = ocr.findIncludeText('今日头条极速版'); if(target) { var rect = target.rect; var screenWidth = screen.getScreenWidth(); var screenHeight = screen.getScreenHeight
群发软件AIWROK软件技巧分享图片二值化封装使用
AIWROK软件技巧分享图片二值化封装使用// 引入 Android 和 OpenCV 的类importPackage(org.opencv.core);importPackage(org.opencv.imgproc);importPackage(org.opencv.android);importClass(android.graphics.Bitmap);function screenshotAndBinarize(width, height, quality, threshold1, threshold2) { // 进行屏幕截图 var bitmap = screen.screenShot(width, height, quality).getBitmap(); // 将 Bitmap 转换为 Open
群发软件AIWROK软件安卓自动化auto__小结方法总汇集
第一个:back按下回退键auto.back();这个代码示例展示了如何调用一个名为 back() 的函数来返回上一页或执行某种“返回”操作。例子:function demoExample() { // 打印信息表明即将返回上一页 printl("即将返回上一页"); // 使用 auto.back() 返回上一页 auto.back(); } // 调用示例函数 demoExample();代码说明:function demoExample() { ... }:定义了一个名为 demoExample 的函数,该函数没有参数。printl("
群发软件floatUI自定义极度美化悬浮窗
/* 欢迎使用AiWork安卓自动化IDE 帮助文档: http://help.autoapp.net.cn 官方地址: www.aiwork24.com qq群: 743723025*/ // 定义一个名为悬浮窗的构造函数function 悬浮窗() {}// 创建一个悬浮窗实例var float = new 悬浮窗()// 定义一个全局变量用于控制停止状态var 全局_停止 = false// 为悬浮窗构造函数的原型添加create方法,用于创建悬浮窗界面悬浮窗.prototype.create = function () { // 创建一个floatUI实例,f
群发软件AIWROK软件agent代理模式ADB方法集合
第一个例子:开启代理模式判断agent.start()agent.start() 函数用于开启代理模式,需 root 权限,无需参数。此函数执行后会返回一个布尔值:如果成功返回 true,否则返回 false。下面是一个可能的使用例子:// 尝试启动代理模式 let result =agent.start(); printl(result); if (result) { console.log("代理启动成功!"); } else { console.log("代理启动失败,请检查是否具有root权限。"); }此代码尝试启动代理模式,
群发软件用在AIWORK软件代码中的实用符号分类整理
var 任务进行中 = true;var 倒计时已启动 = false;var 任务三已执行 = false;var 任务一定时器, 任务二定时器;function 任务一() { print.log("🚀▶️ 准备执行任务一"); // 使用您的环境专用输出 function 执行任务一() { if (!任务进行中) { clearTimeout(任务一定时器); return; } print.log("✅🔁 任务一执行中..."); 任务一定时器 =
群发软件AIWROK多线程方法UI线程对象方法
AIWROK多线程方法UI线程对象方法名称new thread()作用多线程方法权限root键鼠无障碍语法new thread()参数类型是/否说明线程对象对象是创建一个线程对象返回类型是/否说明对象/对象成功对象失败函数线程对象方法类型是/否说明.runJsCode(fun, name )函数/字符是fun 执行的函数name 执行线程名称返回类型是/否说明无无成功失败文件线程对象方法类型是/否说明. runJsFile (js, name )字符是js 执行的js文件name 执行线程名称返回类型
群发软件AIWROK软件常用数组方法小结汇集方法
/* 官方交流群号711841924 *//* 安卓手机 Android 和Rhino1.7.13 和ES5 JavaScript环境 */var 数组 = {};// 1. 元素升序(小到大)数组.元素升序 = function(arr) { try { if (!Array.isArray(arr)) throw new Error("需要数组"); return arr.slice().sort(function(a,b){return a-b;}); } catch(e) { printl("[错误] "+e.message); return null; }};// 2. 元素降序(大到小) 数组.元素降
群发软件AIWROK软件多线程thread1.runJsFile例子
本帖最后由 群发软件 于 2025-4-15 09:24 编辑 T = time.nowStamp();// 正确启动两个线程(线程名必须不同!)var thread1 = new thread(); // 线程对象1var thread2 = new thread(); // 线程对象2thread1.runJsFile('线程1.js', 'worker1'); // 线程名用"worker1" thread2.runJsFile('线程2.js', 'worker2'); // 线程名用"worker2"// 监控循环(10秒后停止线程1)while (true) { printl("正常运行"); sleep.millisecon
群发软件AIWROK软件支持的Java标准库和Android SDK库
特别是针对Android开发时导入的各种类。这些类分别属于Java标准库和Android SDK库,用于处理不同的功能需求。下面是对这些代码的详细说明://java类//importClass(java.math.Session);//importClass(java.math.Transport);//importClass(java.math.BigInteger);//importClass(java.math.internet.MimeMessage);importClass(java.sql.Connection);importClass(java.sql.DriverManager);importClass(java.sql.ResultSet);importClass
群发软件AIWROK软件thread使用全局变量控制线程状态
AIWROK软件thread使用全局变量控制线程状态// 安卓手机 Android 和Rhino1.7.13 和ES5 JavaScript环境// Android 环境 Rhinoceros 引擎与 JavaScript 的多线程示例{ // 使用全局变量控制线程状态 var shouldStop = false; // 创建一个 Java 的 Thread 对象 var runnable = new java.lang.Runnable({ run: function() { var count = 0; while (!shouldStop) {
群发软件AIWROK软件HID点击方法的方法集合小结
// 点击坐标// boolean click(int x, int y) 返回值: boolean// 参数: int x: 横坐标 int y: 纵坐标// 案例: hid.click(0, 0)hid.click(0, 0)// 点击百分比坐标// void clickPercent(double arg0, double arg1) 返回值: void// 参数: double arg0: 横坐标 double arg1: 纵坐标// 案例: hid.clickPercent(0, 0)hid.clickPercent(0, 0)// 连续点击// boolean clicks(int x, int y, int times, int delay) 返回值: boolean// 参数: in
群发软件AIWROK软件常用OKHTTP方法小结汇集
群发软件AIWROK软件字符方法集合小结
//字符.分割字符/** * 字符串分割工具模块 - 修正版 * 最后更新:2025-04-02 */var 字符 = { /** * 字符串分割方法 * @param {string} str 要分割的字符串 * @param {string} divide 分隔符 * @returns {Array|null} 分割后的数组或null(错误时) */ 分割字符: function(str, divide) { try { if (typeof str !== 'string') return null; if (typeof divide !== 'string')
群发软件AIWROK软件数学方法集合小结
/** * //适用本文档ES5系统安卓 JavaScript引擎Rhino * 数学方法全集 * 运行环境: Android + Rhino 1.7.13 + ES5 */// 定义数学对象var 数学 = {};/** * 二为底的e的对数 * @setting ROOT 代理激活 无障碍 键鼠硬件 * @returns {number} 返回二为底的e的对数 */数学.__二为底的e的对数 = function() { return Math.LOG2E;};/** * 二的平方根 * @setting ROOT 代理激活 无障碍 键鼠硬件 * @returns {number} 返回二的平方根 */数
群发软件AIWROK软件应用方法集合小结
// 应用管理工具集const 应用 = {};// 模拟日志函数const LOG = { info: function(msg) { printl(' ' + msg); }, err: function(msg) { printl('[ERROR] ' + msg); }};/** * 停止当前脚本 */应用.停止脚本 = function () { try { LOG.info("尝试停止脚本..."); if (typeof runtime !== 'undefined' && runtime.exit) { LOG.info("使用runtime.exit()停止脚本"); runtime.exit();
群发软件AIWROK软件常见正则方法集合小结
//适用本文档ES5系统安卓 JavaScript引擎Rhinoconst 字符 = { /** * 匹配查找字符串中的内容 * @param {string} str 需要查找的字符串 * @param {string|RegExp} searchvalue 需要查找的字符串或正则表达式 * @returns {Array|null} 成功:返回包含匹配结果的数组,失败:返回null * @example * // 示例1:查找字符串 * var str = "How are you doing you today?"; * var fgh = 字符.匹配查找(str
群发软件AIWORK类语聊智能聊天机器人带意图识别例子演示
类语聊智能聊天机器人带意图识别例子演示 飞桨智能聊天机器人集成指南示例代码转换为实际可用的智能聊天机器人应用。1. 代码结构说明当前代码包含两个主要模块:HTTP工具模块提供基础的HTTP请求功能,用于与飞桨API进行通信: [*]HTTP工具.创建请求() - 创建HTTP请求实例 [*]HTTP工具.设置请求头(http, headers) - 设置HTTP请求头 [*]HTTP工具.POST请求(url, data, headers) - 发送POST请求并处理响应 智能聊天机器人模块实现
群发软件AIWROK软件时间方法集合小结
AIWROK软件时间方法集合小结//适用本文档ES5系统安卓 JavaScript引擎Rhinoconst 时间 = { /** * 获取当前时间戳 * @returns {number} 返回当前的时间戳(毫秒) * @example * var timestamp = 时间.当前时间戳(); * printl(timestamp); // 输出类似: 1677649423000 */ 当前时间戳: function() { return Date.now(); }, /** * 格式化时间为指定格式 * @param {Date|number|str
群发软件IOS苹果TabView视图和Horizontal水平布局控件
IOS苹果TabView视图和Horizontal水平布局控件 导航条视图模式可以支持多个页面标签切换案例:创建TAB视图显示视图function show(function fun)参数 func :ui显示以后调用的方法设置tabtab.setTitles(["首页", "关于", "我的"])//关闭视图tab.dismiss()添加子视图tab.addView(tabindex,view)参数tabindex:tab的序号从0开始参数 view:子视图案例Horizontal水平布局控件用于横向放置多个控件案例:
群发软件苹果熟悉layout线性布局和IOS苹果View视图
本帖最后由 群发软件 于 2025-3-27 07:34 编辑 线性布局是垂直或者水平布局类似网格 水平布局 比如就是一行可以放多个控件文本框:按钮:单选框:复选框类似上面这样一行可以放多个控件的就是水平布局垂直布局就是一行只能放一个元素文本框按钮单选复选混合布局,就是水平和垂直嵌套就可以实现复杂的界面例如一个登录界面,先创建一个垂直布局 ,每个垂直布局的每一行再放一个水平布局用户名————————密码————————
群发软件AIWROK软件生成椭圆曲线手势
这段代码定义了一些用于生成和执行贝塞尔曲线手势的函数。具体来说,代码分为以下几个部分: 1随机数生成函数: 这个函数 random(a, b) 使用 rand.randNumber(a, b) 来生成一个在 a 到 b 之间的随机数。不过,在完整的代码中,rand.randNumber 需要是一个已定义的函数或库方法。 2椭圆曲线点生成器: 函数 generateEllipticPoints(a, b, xStart, xEnd, step) 用于根据椭圆曲线的参数 a 和 b,在指定的 x 范围内生成一系列的点。
群发软件AIWROK软件屏幕自动化操作方法汇集
代码的简要说明和一些注意事项: [*]MLKitOcr 文字识别: [*]代码中使用了 MLKitOcr 方法来进行文字识别。'zhs' 和 'zh' 都是中文的识别代码,但通常使用 'zh'。 [*]识别结果通过 getAllString() 方法获取,然后打印出来。 [*]使用完截图后,记得调用 recycle() 方法来释放资源。 [*]截图并压缩: [*]使用 screenShot 方法可以指定截图的尺寸和压缩质量。 [*]检查截图是否成功后再进行后续操作。 [*]计算面
群发软件苹果IOS在IDE中配置AIWork直播插件的详细图文教程
在IDE中配置AIWork直播插件的详细图文教程以下是关于在集成开发环境(IDE)中配置AIWork直播插件的详细步骤说明,帮助您顺利完成设置。第一步:安装IDE1. 下载并安装IDE· 下载安装包:访问官方网站或可信来源下载最新版本的IDE安装包。· 安装步骤:a. 双击安装包文件,按照提示完成安装。b. 安装完成后,重启计算机以确保环境变量生效。· 验证安装:打开IDE,检查是否能正常运行,确保所有组
群发软件AIwok软件苹果IOS手机初始化设置和IOS HTTP接口
配置要求:IDE AIWORK >3.25手机 >= iphone6sIOS版本 >=IOS15(ios15不支持画中画日志,16以上支持)苹果HID硬件必须设置:自动息屏:必须关闭,不然截屏权限会自动关闭蓝牙:必须打开辅助触控:必须打开 (设置->辅助功能->触控->辅助触控->打开)软件安装1.下载tf并安装https://testflight.apple.com/join/1sVURYPb或者扫二维码下载 安装完tf以后 再安装aiwork初始化第一步 硬件连接手机,选择硬件第二步 开启辅助触
群发软件AIWROK软件多线程协作示例代码解析
AIWROK软件多线程协作示例代码解析 详细说明 [*]线程对象创建 [*]使用new thread()创建两个独立线程对象 [*]dataThread用于数据处理,logThread用于日志记录 [*]每个线程有独立的执行上下文和生命周期 [*]数据生成线程 [*]通过runJsCode方法执行匿名函数 [*]使用for循环生成1-5的序列数据 [*]java.lang.Thread.sleep(1000)实现1秒间隔(Rhino引擎特性) [*]线程命名为"数据线程"便于调试识别 [*]日志记录线程
群发软件AiWork软件下载蓝奏云OCR文件到文件夹
这段代码是一个用于从蓝奏云(Lanzou)下载文件的自动化工具脚本,主要基于JavaScript编写,并且是在一个安卓自动化环境中运行的,例如使用AiWork这样的自动化IDE。代码中定义了一个主要的函数downloadLanzouFile,它接受三个参数:文件的URL地址url,保存文件的路径saveFilePath,以及最大重试次数maxRetries(如果未提供,函数默认设置为5次)。代码的主要功能和步骤如下: [*]初始化和配置: [*]定义了蓝奏云的备用域
群发软件setTimeout__方法异步延迟加载函数
这段代码定义了一个简单的任务链,模拟了一个从数据查询到数据处理再到数据保存的流程。代码中使用了runTime.setTimeout来模拟每个任务的执行耗时。以下是代码的详细说明: [*]taskOne函数:这是第一个任务,负责开始数据查询。 [*]使用printl函数打印一条消息,表示任务一即将开始。 [*]使用runTime.setTimeout函数来模拟数据查询的过程,设置的延迟时间为3秒(3000毫秒)。 [*]在3秒后,生成一个模拟数据字符串"查
群发软件floatUI悬浮窗 实用示例合集
floatUI悬浮窗 实用示例合集如何使用 floatUI 创建不同的 UI 组件,并为它们设置点击事件。每个示例都展示了不同的 UI 布局和事件处理逻辑。示例 1: 创建一个带有多个按钮的垂直布局,并为每个按钮设置不同的点击事件var f1 = new floatUI(); f1.loadSXML(` <vertical> <button text="按钮1" id="button1"/> <button text="按钮2" id="button2"/> <button text="按钮3"
群发软件AIWROK软件找图__方法小汇集
方法一:定义图像查找函数 [*]功能:在指定的查找区域内查找与模板图像相似度达到设定值的目标,并自动点击该目标的中心位置。 [*]参数: [*]searchRegion:查找区域的相对坐标,格式为 [x1, y1, x2, y2],其中 (x1, y1) 是左上角坐标,(x2, y2) 是右下角坐标。 [*]templateImage:模板图像的Base64编码字符串。 [*]similarity:相似度阈值,用于判断是否匹配。 [*]流程: [*]获取屏幕截图并转换为Mat格
群发软件awirok软件找色__方法小汇集
群发软件AIWORK 软件全功能 OCR 查找区域功能代码示例
    // 第一个示例:获取屏幕截图并进行 OCR 文字识别(简体中文)var img1 = screen.screenShotFull();var ocr1 = img1.MLKitOcr('zhs');var text1 = ocr1.getAllString();printl(text1);img1.recycle();/*说明:- 这是一个最基本的 OCR 示例。- 使用 MLKitOcr 方法通过简体中文词库识别截图中的文字。- 最终输出识别到的全文本信息。*/// 第二个示例:指定区域内的 OCR 文字识别(中文)var img2 = screen.s
群发软件AiWROK软件里的OpenCV图片分辨率压缩和质量压缩
// 导入必要的Android和OpenCV类importClass(android.graphics.Bitmap);importClass(java.io.File);importClass(org.opencv.core.Core);importClass(org.opencv.core.Mat);importClass(org.opencv.core.Size);importClass(org.opencv.imgproc.Imgproc);// 全屏截图var img = screen.screenShotFull();if (img.isNull()) {printl("截图失败");exit();}// 原始图片信息var originalPath = "/sdcard/original.jpg";img.save(originalP
群发软件定时任务示例:使用 setInterval 和 clearInterval 实现多种功能
1. 倒计时功能var countdownTime = 10; var countdownInterval; function updateCountdown() { if (countdownTime > 0) { console.log("剩余时间: " + countdownTime + "秒"); countdownTime--; } else { clearInterval(countdownInterval); console.log("倒计时结束!"); } }用法启动:startCountdown()停止:stopCountdown()应用场景游戏倒计时、会议提醒、考试计时、烹饪计时等。2. 实时时
群发软件AIWORK软件将数组↔互转字符串
AIWORK软件将数组↔互转字符串1.方法将数组转换为字符串// 定义函数function myFunction() {// 定义一个包含水果名称的数组var fruits = ["Banana", "Orange", "Apple", "Mango"];console.log("原始数组: ", fruits);// 使用 toString 方法将数组转换为字符串var str = fruits.toString();console.log("转换后的字符串: ", str);// 返回转换后的字符串return str;}// 调用函数var result = myFunction();2. 将数组互转字符串/
群发软件Boolean对象构造AIWROK函数深度解析
本类目代码集合:  //第一个,boolean.constructor_函数的引用 // 创建布尔对象 var myBool = new Boolean(true); // 访问构造函数 printl(myBool.constructor); // 输出: function Boolean() { [native code] } // 确认构造函数的类型 printl(myBool.constructor === Boolean); // 输出: true //第二个,boolean.toString___布尔转字符 // 创建一个 Boolean 对象 var boolTrue = new Boolean(true); v
群发软件AIWROK软件随机时间和随机倒计时用法技巧分享
群发软件安卓自动化[auto]大集合第一部
安卓自动化[auto]大集合第一部第一个:back按下回退键auto.back();这个代码示例展示了如何调用一个名为 back() 的函数来返回上一页或执行某种“返回”操作。例子:function demoExample() { // 打印信息表明即将返回上一页 printl("即将返回上一页"); // 使用 auto.back() 返回上一页 auto.back(); } // 调用示例函数 demoExample(); 代码说明:function demoExample() { ... }:定义了一个名
群发软件AIWROK软件随机位置范围点击和范围随机拖动
   /* * 随机位置点击函数 * @param {number} x - 点击位置的百分比 X 坐标 * @param {number} y - 点击位置的百分比 Y 坐标 * @param {number} x范围 - X 坐标的随机范围 * @param {number} y范围 - Y 坐标的随机范围 */ function 随机位置点击(x, y, x范围, y范围) { // 将百分比坐标转成真实坐标 var x1 = screen.percentToWidth(x); var y1 = screen.percentToHeight(y); /
群发软件AIWORK软件FTP完整例子自动链接可以上传可以下载
AIWORK软件FTP完整例子自动链接可以上传可以下载/* 欢迎使用AiWork安卓自动化IDE 帮助文档: http://help.autoapp.net.cn 官方地址: www.aiwork24.com qq群: 743723025 */ // 加载FTP库 // 通过rhino.loadDex方法加载名为"ftp.dex"的Java库文件,该文件包含了用于FTP操作的类 rhino.loadDex(project.getResourcesPath() + "ftp.dex"); // 导入所需的FTP操作类和Java IO包 importClass(org.apache.common
群发软件AWIROK软件:如何实现OCR找字并点击功能?
var img = screen.screenShotFull(); var ocrres = img.paddleOCR(640, [0, 0, 1, 1]); var dect = ocrres.findIncludeText('今日头条'); if (dect != null) { console.log('今日头条'); dect.click(); // 点击检测到的“今日头条”区域 dect.hidClick(); sleep.millisecond(3000); // 暂停3秒 } else { // 找图返回目标数组 var detects = opencv.findImagesEx('图色982357继续安装.cv');
群发软件手机改了分辨率后有误差用公式计算加减还原点击
有的人用改分辩率软件,更改了手机的分辩率,为了让所有手机通用一种点击方法,计算偏差,可以用这段代码实现。两种方法如下:第一种方法:function calculateFunction(inputValue) { function leastSquaresFit(x, y) { var n = x.length; var sumX = 0; var sumY = 0; var sumXY = 0; var sumX2 = 0; for (var i = 0; i < n; i++) { sumX += x;
群发软件原生webview的h5如何跟aiwork交互
原生webview的h5如何跟aiwork交互 原生activity和h5交互案例.zip void runJs(function code)h5执行app JS脚本window.at.runJs(function (){ //这里写ATjs代码 printl("你好"); auto.home();}.toString());void runJsFile(String file) H5运行APP JS文件window.at.runJsFile('主脚本.js');void callFunction(String funname,String arg) H5执行脚本方法window.at.callFun('main',"hello");Str
群发软件AIWORK软件图片二值化封装使用方法说明
群711841924// 引入 Android 和 OpenCV 的类 importPackage(org.opencv.core); importPackage(org.opencv.imgproc); importPackage(org.opencv.android); importClass(android.graphics.Bitmap); function screenshotAndBinarize(width, height, quality, threshold1, threshold2) { // 进行屏幕截图 var bitmap = screen.screenShot(width, height, quality).getBitmap(); // 将 Bitmap 转换为 OpenCV
群发软件使用AIWORK的ADB命令执行: 实现安卓设备的远程命令
第一个例子:开启代理模式判断agent.start()agent.start() 函数用于开启代理模式,需 root 权限,无需参数。此函数执行后会返回一个布尔值:如果成功返回 true,否则返回 false。下面是一个可能的使用例子: // 尝试启动代理模式 let result =agent.start(); printl(result); if (result) { console.log("代理启动成功!"); } else { console.log("代理启动失败,请检查是否具有root权限。"); } 此
群发软件理解Activity:安卓应用中的关键组件
在安卓开发中,Activity 是一个非常重要的组件,主要用于以下几个方面:用户界面展示:每个 Activity 通常代表一个完整的屏幕或界面,用户与应用的交互主要通过 Activity 实现。例如,一个邮件应用可能包含一个显示邮件列表的 Activity,以及另一个用于阅读邮件内容的 Activity。生命周期管理:Activity 有一个生命周期,即创建、启动、恢复、暂停、停止和销毁等状态。开发者可以通过重写
群发软件AIWORK全能图像处理开发指南:从截图采集到OCR识别的全链路实现
1.截取屏幕的全屏截图:var img = screen.screenShotFull(); 这行代码用于截取当前屏幕的全屏截图,并将截图存储在变量img中。2.文字识别,默认语言为中文:var ocr = img.MLKitOcr('zh'); printl(ocr.getJsonString()); 使用MLKitOcr方法对截图img进行文字识别,指定语言为中文’zh’,并将识别结果以JSON字符串形式打印出来。3.获取图片大小(以字节为单位):var size = img.byteSize(); printl('图片大小: ' + size + ' 字
群发软件AIWROK软件中的okHttp上传文件详解
以这个网站为例子https://ocr.wdku.net/我们首先抓包上传的参数通过以上抓包我们分析出 几个关键点第一:上传的url是 https://ocr.wdku.net/upload第二:二进制的参数名字是 file第三:其他参数user,name,from,fileName现在使用okhttp上传方法以此填写参数var http1=new okHttp(); var fromdata= new map()//其他参数使用map格式 fromdata.add("user","default") fromdata.add("name","t019bf9f2ac19af88b0.webp.png_173915
群发软件通过HTTP接口实现屏幕连续点击功能的易语言代码示例
.版本 2 .支持库 eHTTP .程序集 窗口程序集_启动窗口 .子程序 _启动窗口_创建完毕 .子程序 发送HTTP请求 .参数 请求URL, 文本型 .局部变量 响应内容, 文本型 // 创建HTTP请求对象 HTTP请求对象 = HTTP请求 () // 设置请求URL HTTP请求对象.设置URL (请求URL) // 发送GET请求 响应内容 = HTTP请求对象.发送GET () // 显示响应内容(可选) 信息框 (响应内容, #信息图标, “响应内容”) .子程序
群发软件实现AIWork软件开机自动启动且不弹出界面
这个代码的主要作用是,手机一开机就自动不弹界面,自动开始运行脚本,如果你想定时脚本,也是需要先打开脚本的,这个需要自己在主脚本的JS运行才可以// 自启动逻辑if (autoStar == true) { printl("开机自启动"); Import("主脚本.js");} else { // 加载主界面 var win = window.loadUI("主界面.ui"); win.show();}这段代码主要用于设置一个应用程序在开机时是否自动启动。代码逻辑如下: [*]代码首先检查变量 autoS
群发软件AIWORK+图鉴:点选验证码智能识别系统集成指南
详细版:function sendImageToAPI(username, password, typeid) { var url = "http://api.ttshitu.com/predict"; // API地址 // 截取全屏图像并裁剪验证码区域 var img = screen.screenShotFull().cutImagePercent(0.17, 0.412, 0.83, 0.57).toBase64(); // 准备POST请求的数据 var postData = JSON.stringify({ username: username, password: password, typeid: t
群发软件MuMu 模拟器借助 ADB 桥接与 AIWROK 软件成功连接的步骤详解
MuMu模拟器桥接ADB模式连接AIWROK软件教程:他模拟器官方网站:https://mumu.163.com/ 第一步准备工作, 同时开多个模拟器会导致端口冲突,新手先折腾一个,成功后再试多开。 如果之前开过其他模拟器(雷电、夜神等),先全部关掉!先确定你这里只有一个模拟器,因为多个,他可能端口不同的,一个连接上了,其它也能链接上,最好是先一个先折腾着,这样后面就简单了。 然后开启他的网络桥接状态。打开MuMu模拟器 → 点击右上角
群发软件JavaScript中贝塞尔曲线的实现与应用
随机数生成函数 function random(a, b) { return rand.randNumber(a, b); } /** * @param time_ms {number} 执行时间 ms 例如 3000 * @param t {number} 间隔系数 0-1 间, 越小线条线条越圆润,计算量越大, 例如 0.005 * @param pt {number[][]} 控制点坐标的二维数组 例如 [[137,169],[140,283]] */ function bezier(time_ms, t, pt) { var gesture1 = new path(); // 创建一个手势对象 gesture1.se
群发软件键鼠.随机百分比点击方法结合屏幕百分比和随机偏移,实现精准且自然的
第一个,键鼠HID随机点击例子const 键鼠 = {}; 键鼠.点击 = function (x, y) { if (typeof x === "undefined") return false; if (typeof y === "undefined") return false; return hid.click(x, y); } 键鼠.随机点击 = function (x, y, random) { if (typeof x === "undefined") return false; if (typeof y === "undefined") return false; let random_s = random || 10; let x
群发软件应用关闭函数的设计
第一个:定义一个关闭当前窗口的函数// 定义一个关闭当前窗口的函数 function close() { // 本示例创建一个带有一个按钮的窗口,点击按钮关闭当前窗口 // 初始化一个新的活动(窗口) var ac = new activity(); // 加载布局代码,使用 LinearLayout 替换 vertical ac.loadXML(` <LinearLayout> <Button id="button1" text="第一个按钮"/> </LinearLayout>
群发软件多点屏幕颜色检测:10秒内变化监控
群发软件智能链接:在安卓上无缝切换快手与抖音
1.这是一段快手的意图跳转例子// 导入包 importClass(Packages.android.content.Intent); importClass(Packages.android.net.Uri); importClass(Packages.android.content.ActivityNotFoundException); importClass(Packages.android.widget.Toast); importClass(Packages.android.os.Handler); importClass(Packages.android.os.Looper); // 设置快手用户页面的URL var userId = "2037335125"; var url = "kwai://prof
群发软件在AIWROK软件中使用OkHttp设置HTTP请求头中的Cookie并输出
群发软件监听广播事件:onBroadcastEvent 方法详解
本帖最后由 群发软件 于 2025-1-16 09:43 编辑 event事件侦听使用 onBroadcastEvent 方法的示例:// 监听广播事件 event.onBroadcastEvent(function(msg) { // 在接收到消息时打印出来 print(msg); }); 说明:onBroadcastEvent 是一个用于监听广播事件的方法。它接收一个函数作为参数,该函数会在事件触发时执行。在这个例子中,当收到消息时,打印该消息。这个示例演示了如何实现一个简单的事件监听
群发软件自动下载与安装:多线程管理指定文件夹APK和图片文件的下载完整性检查
自动下载与安装:多线程管理指定文件夹APK和图片文件的下载完整性检查
群发软件用AiWork如何写出一个一个播放器呢?
用AiWork如何写出一个一个播放器呢? 用软件可以写出一个简易的播放器,专门听歌甚至占用内存极少,极度容易的播放器例子。 传到手机只需要播放就可以了。这个如果您希望从一个MP3列表中逐个播放文件, 您可以先创建一个包含所有MP3文件路径的数组, 然后使用循环或递归的方式来遍历并播放这些文件。这里是一个示例代码,展示了如何实现这一功能: 这段代码首先定义了一个mp3List数组, 包含了您想要播放的M
群发软件蓝奏云-文件下载(2.8.9版本)

QQ|( 京ICP备09078825号 )

本网站信息发布软件,是可以发布论坛,发送信息到各大博客,各大b2b软件自动发布,好不夸张的说:只要手工能发在电脑打开IE能发的网站,用这个宣传软件就可以仿制动作,进行推送发到您想发送的B2B网站或是信息发布平台上,不管是后台,还是前台,都可以进行最方便的广告发布,这个广告发布软件,可以按月购买,还可以试用软件,对网站的验证码也可以完全自动对信息发布,让客户自动找上门,使企业轻松实现b2b发布,这个信息发布软件,均是本站原创正版开发,拥有正版的血统,想要新功能,欢迎提意见给我,一好的分类信息群发软件在手,舍我其谁。QQ896757558

GMT+8, 2025-5-1 19:40 , Processed in 0.314534 second(s), 46 queries .

宣传软件--信息发布软件--b2b软件广告发布软件

快速回复 返回顶部 返回列表