C#和JAVA的相同点和不同点

C#和JAVA的相同点和不同点,第1张

C#和Java都支持面向对象,都支持跨平台,都运行在各自的虚拟机上,C#有linQ,属性器,索引器,迭代器,delgate匿名函数,指针,函数指针,await,Java没有,Java有匿名内部类和引用类型的枚举类,C#没有

你只需要知道两点

堆中存放具体数据

栈中存放你所命名的变量名字

既然叫匿名函数

自然没有名字

所以这就是在堆里有具体数据

而栈中没有名字指向这个数据的意思

从Java到Swift还是比较简单的,相比Object-C,Swift和Java的语法更加接近,和最近的Kotlin就更像了。Swift同时支持面向对象编程和函数式编程。Swift比Java功能更加强大,用法更加友好。网上有一份Java和Swift的粗略对比:

基础部分

1Swift没有main函数,这个有点像脚本语言。Swift程序的默认入口是mainswift文件,在iOS应用中,则通常标记了@UIApplicationMain的AppDelegateswift文件。可以类比到Android中,在AndroidManifestxml中定义的Application。

2Swift不需要定义行结束符,这个是像脚本语言一样。

3Swift使用var定义变量,一般无需指定具体的数据类型,编译器会自行判断。遇到编译器无法判断的情况,需要自己显式指定。

4Swift用let定义常量,Java里面是static final。

5array跟Java中的array是一样的概念。dictionary就是Java中的map。dictionary的取值的方式是dictionary[key],接口就像array一样,简洁方便。

6nil在swift中就类似Java中的null。nil是没有初始化成功,是没有值。

7optional value是指该value的值可以是nil,Swift默认一个var是不能赋值nil,除非它声明了optional。optional不能直接输出,而必须unwrap,形如optionalValue!。有点类似于Java中打包好的null判断。也可以用!代替声明一个无需unwrap的var。

逻辑控制

1Swift的switch 语法和Java及C++很像,但是它没有break,他命中一个case后会自动退出switch。对于几个不同case同样处理的情况,可以case后面连续几个condition,用逗号隔开。

2Swift的switch支持运算,运算的话,就是说不仅仅是equal,而是支持满足特定要求。

3while循环和Java或者C++中基本一致,不过while后面直接写condition,不需要用括号。

4for循环和Java也基本一样,不过也是不需要括号。for循环中,<的用法比较方便。同时还支持_通配符,有点类似与Java中for

each循环。

函数

1函数的定义和Java很不一样。Swift函数的定义形如 func functionName(argName: Type) -> Return Type:

2Swift函数可以返回多个返回值,这个功能真是太猛了。

3Swift函数可以接收不定参数,跟Java基本类似的用法。

4函数可以嵌套,这个是Java或者C++都没有的,挺好用。例如经常有一段逻辑,用一个函数实现太长,在Java或者C++中,通常是会把它拆分成几个函数,保持每个函数短小,功能单一。但是这样拆分的函数并不能很好的表明他们是一个功能的,不够“内聚”。用这种Swift函数嵌套的方式就能较好实现。

5Swift支持函数类型,根据输入参数和返回值确定一个函数类型。函数类型可以让函数像,普通数据类型一样使用。例如函数的参数可以另外一个函数,注意,不是另外一个函数的返回值,而是另外一个函数,只要类型符合即可。这个相当于是函数级别的多态,真的有点猛。

6Swift支持闭包,我觉得可以理解成“匿名函数”,只需要描述输入输出,用in分开输入输出描述,已经函数体,无需定义函数名。

类与结构

1类的构造函数,直接叫init()。类函数调用跟Java,C++基本一样。self相当于Java中的this。

2在Swift中class的成员访问权限控制级别有public, internal, private对应Java中的public, protected, private。

3deinit是析构函数。Java中也有finalize()函数。不过Java的finalize()函数并不确保一定被调用,所以并不推荐override该函数。

4类的继承跟C++有点像,使用:。

5他的setter和getter函数跟Java不太一样,是隐式调用的。我觉得Swift的设计思想是,用户只需关心输入和输出,其他的不用关心。例如此处只需关心需要set或者get。具体的set和get函数则是封装的,无需使用者去关心。又譬如上面提到的method的type,只要定义了输入和输出,就定义了一类method,那就可以对这种type有多种具体实现。

6Swift的枚举和Java类似,本质是一个类,里面可以包含函数。

7Swift的struct和class写法基本一样,区别在于struct传递的是内容的copy,而class传递的是引用。这个厉害啊。

8枚举还支持associated value,这个是Java没有的。

9protocol类似于Java中的interface。

10extension比较强大,甚至变态,可以动态往某个类中增添函数以及成员变量,动态让某个类实现某个protocol,而无需修改该类源代码。Java新增成员变量,新增函数,实现某个interface,Java都只能通过继承实现。而这个直接实现,且对一切该类的对象生效,包括extend之前已经创建的对象。

11Swift泛型和Java类似的,Swift的泛型支持where语句,可以在对类型控制之外,作更加精细的控制。

内存管理

Swift和Java类似,也无需自己管理内存,Swift是由ARC(Automatic Reference Counting)机制来回收内存的,Java是有垃圾回收机制来保证内存被及时回收。但是两者的回收机制有所区别。我的理解是Swift的ARC机制着眼于无效的对象,就是那些没有被任何人引用到的对象。因此,如果两个对象循环引用,就会无法被回收,引起泄露。此时就需要Weak Reference或者Unowned Reference来打破这个环。

而Java的垃圾回收机制,从反面思考,着眼于哪些是有效的对象,即有被GC Root引用到的对象是有效的,其他的都是无效的。因此哪怕有对象相互引用,只要没有被GC Root引用到,都会被垃圾回收器回收掉。从这此处来看,Java的策略更优。也由此可以看到换个角度看问题是多么重要。

1、函数式接口

Java 8 引入的一个核心概念是函数式接口(Functional Interfaces)。通过在接口里面添加一个抽象方法,这些方法可以直接从接口中运行。如果一个接口定义个唯一一个抽象方法,那么这个接口就成为函数式接口。同时,引入了一个新的注解:@FunctionalInterface。可以把他它放在一个接口前,表示这个接口是一个函数式接口。这个注解是非必须的,只要接口只包含一个方法的接口,虚拟机会自动判断,不过最好在接口上使用注解 @FunctionalInterface 进行声明。在接口中添加了 @FunctionalInterface 的接口,只允许有一个抽象方法,否则编译器也会报错。

javalangRunnable 就是一个函数式接口。

@FunctionalInterface

public interface Runnable {

public abstract void run();

}

2、Lambda 表达式

函数式接口的重要属性是:我们能够使用 Lambda 实例化它们,Lambda 表达式让你能够将函数作为方法参数,或者将代码作为数据对待。Lambda 表达式的引入给开发者带来了不少优点:在 Java 8 之前,匿名内部类,监听器和事件处理器的使用都显得很冗长,代码可读性很差,Lambda 表达式的应用则使代码变得更加紧凑,可读性增强;Lambda 表达式使并行 *** 作大集合变得很方便,可以充分发挥多核 CPU 的优势,更易于为多核处理器编写代码;

Lambda 表达式由三个部分组成:第一部分为一个括号内用逗号分隔的形式参数,参数是函数式接口里面方法的参数;第二部分为一个箭头符号:->;第三部分为方法体,可以是表达式和代码块。语法如下:

1 方法体为表达式,该表达式的值作为返回值返回。

(parameters) -> expression

2 方法体为代码块,必须用 {} 来包裹起来,且需要一个 return 返回值,但若函数式接口里面方法返回值是 void,则无需返回值。

(parameters) -> { statements; }

例如,下面是使用匿名内部类和 Lambda 表达式的代码比较。

下面是用匿名内部类的代码:

buttonaddActionListener(new ActionListener() {

@Override

public void actionPerformed(ActionEvent e) {

Systemoutprint("Helllo Lambda in actionPerformed");

}

});

下面是使用 Lambda 表达式后:

buttonaddActionListener(

\\actionPerformed 有一个参数 e 传入,所以用 (ActionEvent e)

(ActionEvent e)->

Systemoutprint("Helllo Lambda in actionPerformed")

);

上面是方法体包含了参数传入 (ActionEvent e),如果没有参数则只需 ( ),例如 Thread 中的 run 方法就没有参数传入,当它使用 Lambda 表达式后:

Thread t = new Thread(

\\run 没有参数传入,所以用 (), 后面用 {} 包起方法体

() -> {

Systemoutprintln("Hello from a thread in run");

}

);

通过上面两个代码的比较可以发现使用 Lambda 表达式可以简化代码,并提高代码的可读性。

为了进一步简化 Lambda 表达式,可以使用方法引用。例如,下面三种分别是使用内部类,使用 Lambda 表示式和使用方法引用方式的比较:

//1 使用内部类

Function<Integer, String> f = new Function<Integer,String>(){

@Override

public String apply(Integer t) {

return null;

}

};

//2 使用 Lambda 表达式

Function<Integer, String> f2 = (t)->StringvalueOf(t);

//3 使用方法引用的方式

Function<Integer, String> f1 = String::valueOf;

要使用 Lambda 表达式,需要定义一个函数式接口,这样往往会让程序充斥着过量的仅为 Lambda 表达式服务的函数式接口。为了减少这样过量的函数式接口,Java 8 在 javautilfunction 中增加了不少新的函数式通用接口。例如:

Function<T, R>:将 T 作为输入,返回 R 作为输出,他还包含了和其他函数组合的默认方法。

Predicate<T> :将 T 作为输入,返回一个布尔值作为输出,该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(与、或、非)。

Consumer<T> :将 T 作为输入,不返回任何内容,表示在单个参数上的 *** 作。

例如,People 类中有一个方法 getMaleList 需要获取男性的列表,这里需要定义一个函数式接口 PersonInterface:

interface PersonInterface {

public boolean test(Person person);

}

public class People {

private List<Person> persons= new ArrayList<Person>();

public List<Person> getMaleList(PersonInterface filter) {

List<Person> res = new ArrayList<Person>();

personsforEach(

(Person person) ->

{

if (filtertest(person)) {//调用 PersonInterface 的方法

resadd(person);

}

}

);

return res;

}

}

为了去除 PersonInterface 这个函数式接口,可以用通用函数式接口 Predicate 替代如下:

class People{

private List<Person> persons= new ArrayList<Person>();

public List<Person> getMaleList(Predicate<Person> predicate) {

List<Person> res = new ArrayList<Person>();

personsforEach(

person -> {

if (predicatetest(person)) {//调用 Predicate 的抽象方法 test

resadd(person);

}

});

return res;

}

}

3、接口的增强

Java 8 对接口做了进一步的增强。在接口中可以添加使用 default 关键字修饰的非抽象方法。还可以在接口中定义静态方法。如今,接口看上去与抽象类的功能越来越类似了。

默认方法

Java 8 还允许我们给接口添加一个非抽象的方法实现,只需要使用 default 关键字即可,这个特征又叫做扩展方法。在实现该接口时,该默认扩展方法在子类上可以直接使用,它的使用方式类似于抽象类中非抽象成员方法。但扩展方法不能够重载 Object 中的方法。例如:toString、equals、 hashCode 不能在接口中被重载。

例如,下面接口中定义了一个默认方法 count(),该方法可以在子类中直接使用。

public interface DefaultFunInterface {

//定义默认方法 countdefault int count(){

return 1;

}

}

public class SubDefaultFunClass implements DefaultFunInterface {

public static void main(String[] args){

//实例化一个子类对象,改子类对象可以直接调用父接口中的默认方法 count

SubDefaultFunClass sub = new SubDefaultFunClass();

subcount();

}

}

静态方法

在接口中,还允许定义静态的方法。接口中的静态方法可以直接用接口来调用。

例如,下面接口中定义了一个静态方法 find,该方法可以直接用 StaticFunInterface find() 来调用。

public interface StaticFunInterface {public static int find(){

return 1;

}

}

public class TestStaticFun {

public static void main(String[] args){

//接口中定义了静态方法 find 直接被调用

StaticFunInterfacefine();

}

}

//定义一个变量并存入字符串:不能超过20字符

ExtformVTypesmax331Text = '不能超过20字符';

//定义一个有参数的匿名函数并把匿名函数命名为:ExtformVTypesmax331

ExtformVTypesmax331 = function(v){

var max = 20;//定义一个变量max并赋值20

var zh = /[<>\/\'\";\%\\_\s\t\xa0\u3000]/; //定义一段正则表达式

if(vlen() <= max){ //判断参数v的长短是否小于等于max即20

alert("ssssssssssssssss");//d出窗口窗口内容为:ssssssssssssssss

//将ExtformVTypesmax331Text 重新赋值,内容为:不能包含空格和/<>;%_单双引号特殊字符!

ExtformVTypesmax331Text = '不能包含空格和/<>;%_单双引号特殊字符!';

return !zhtest(v);//执行正则表达式验证参数v的内容将结果的反面作为返回值

}else{

return false;//若参数v长度大于20则进入else并返回false

}

};

解释完毕。。。

==code: setTimeout(arguments[0],arguments[1]) ==exp: setTimeout("function(){alert(0)}",1000) ==说明 arguments[0]: 为 函数的 字符串格式,这个部分最不好掌握,如果写成的形式是 alert(0) 之类的,则一运行到这部就会执行 alert(0) setTimeout 函数行同虚设。 如果写成 alert ,又不能传递参数,所以用 function(){/code/} 匿名函数。 arguments[0]: 为 执行间隔时间 单位为 毫秒 1000 的话就是 1秒。 ---- 这个函数就是执行一次的,要重复执行的话应当使用 setInterval

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/12188283.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存