Python和Java有趣的语法对比(2)——实例化是否调用基类的构造函数

Python和Java在子类实例化上也有区别,看下面这个例子:

Python版本

class A:
    def __init__(self):
        print("A的构造函数")

    def sayhello(self):
        print("Hello A")

class B(A):
    def __init__(self):
        print("B的构造函数")

    def sayhello(self):
        print("Hello B")


b = B()
b.sayhello()
a = A()
a.sayhello()

输出:

C:\Users\long\Desktop\src\test>python3 test.py
B的构造函数
Hello B
A的构造函数
Hello A

Java版本

public class T1{
    public static void main(String args[]){
        B b =  new B();
        b.sayhello();
        A a = new A();
        a.sayhello();
    }
}

class A{
    A(){
        System.out.println("A的构造函数");
    }
    void sayhello(){
        System.out.println("Hello A");
    }
}

class B extends A{
    B(){
        System.out.println("B的构造函数");
    }
    void sayhello(){
        System.out.println("Hello B");
    }
}

输出:

C:\Users\long\Desktop\src\test>javac -encoding UTF8 *.java

C:\Users\long\Desktop\src\test>java T1
A的构造函数
B的构造函数
Hello B
A的构造函数
Hello A

这里体现了Java有趣的地方,对于类继承,Java实例化子类的时候,不仅会调用子类的构造函数,还会自动调用父类的构造函数,而调用子类的实例方法却不会调用父类的实例方法。在这一点上,Python比较符合人的直观感受,都是调用的实例对应的方法,不管是构造函数还是实例方法。

Python和Java有趣的语法对比(1)——构造函数默认参数

一直在用Python,很少用Java,现在学习Android,为了Native App的流畅性,不得不用Java了。

普通语法上,Python和Java基本可以完全对译,无非是动态类型和静态类型的区别,但是面向对象上,两者的区别就很有意思了。

今天我们来研究一下构造函数默认参数这个话题。举个例子:

如果我们想在类方法执行过程中,有时看到一些debug信息,有时不想看到,而不想每次都重复写输出语句之后再删除,该怎么办呢?

先来看看Python实现:

class Test:

    def __init__(self, debug=False):
        self.debug = debug

    def test_add(self, numa, numb, debug=False):
        if self.debug or debug:
            print("test_add")
            print("numa:" + str(numa))
            print("numb:" + str(numb))
        return numa + numb

    def test_minus(self, numa, numb, debug=False):
        if self.debug or debug:
            print("test_minus")
            print("numa:" + str(numa))
            print("numb:" + str(numb))
        return numa - numb


t = Test()
print(t.test_add(1, 2))
print(t.test_minus(1, 2))

输出:

$ python3 test.py
3
-1

如果想输出一个类里的所有debug,只需要在实例化的时候设置参数就可以了。

1
2
3
t = Test(debug=True)
print(t.test_add(1, 2))
print(t.test_minus(1, 2))

输出:

$ python3 test.py
test_add
numa:1
numb:2
3
test_minus
numa:1
numb:2
-1

如果只想debug某个函数,只需要调用函数的时候设置参数就可以了。

1
2
3
t = Test()
print(t.test_add(1, 2, debug=True))
print(t.test_minus(1, 2))

输出:

$ python3 test.py
test_add
numa:1
numb:2
3
-1

如果用Java实现类似的效果,该怎么办呢?要注意到: Java不支持默认参数

public class T1{
    public static void main(String args[]){
        Test t = new Test();
        System.out.println(t.test_add(1, 2, false));
        System.out.println(t.test_minus(1, 2, false));
    }
}

class Test{
    boolean debug=false;

    void set_global(boolean debug){
        this.debug = debug;
    }

    int test_add(int numa, int numb, boolean debug){
        if(this.debug || debug){
            System.out.println("test_add");
            System.out.println("numa:" + numa);
            System.out.println("numb:" + numb);
        }
        return numa + numb;
    }

    int test_minus(int numa, int numb, boolean debug){
        if(this.debug || debug){
            System.out.println("test_minus");
            System.out.println("numa:" + numa);
            System.out.println("numb:" + numb);
        }
        return numa - numb;
    }
}

输出:

long@iphone7 MINGW64 ~/Desktop/src/test
$ javac *.java

long@iphone7 MINGW64 ~/Desktop/src/test
$ java T1
3
-1

设置类的debug参数。

1
2
3
4
5
6
7
8
public class T1{
    public static void main(String args[]){
        Test t = new Test();
        t.set_global(true);
        System.out.println(t.test_add(1, 2, false));
        System.out.println(t.test_minus(1, 2, false));
    }
}

输出:

long@iphone7 MINGW64 ~/Desktop/src/test
$ javac *.java

long@iphone7 MINGW64 ~/Desktop/src/test
$ java T1
test_add
numa:1
numb:2
3
test_minus
numa:1
numb:2
-1

debug某个函数。

1
2
3
4
5
6
7
public class T1{
    public static void main(String args[]){
        Test t = new Test();
        System.out.println(t.test_add(1, 2, true));
        System.out.println(t.test_minus(1, 2, false));
    }
}

输出:

long@iphone7 MINGW64 ~/Desktop/src/test
$ javac *.java

long@iphone7 MINGW64 ~/Desktop/src/test
$ java T1
test_add
numa:1
numb:2
3
-1

这也就意味着,由于没有默认参数机制,Java要实现这样的debug,必须要为每个函数设定一个debug参数,总不能每个方法都写一个函数重载吧?要不,就利用IDE进行一遍一遍的单步调试??

Java带包编译源文件

如果在java代码中给出package,直接编译生成的class文件会无法运行,提示 “错误: 找不到或无法加载主类”

目录结构:

Desktop/src/test/T1.java
Desktop/src/test/T1.class

解决办法如下:

1
2
3
4
5
6
package src;
public class T1{
    public static void main(String args[]){
        System.out.println("Hello World");
    }
}
>> long@iphone7 MINGW64 ~/Desktop
>> $ javac -d . src/test/T1.java

>> long@iphone7 MINGW64 ~/Desktop
>> $ java src.T1
>> Hello World

Ubuntu命令行连接wifi

>> cd /usr/local/bin/
>> cd /home/long
>> wpa_passphrase SSID PWD > /home/long/wifi.conf
>> sudo emacs /etc/network/interfaces
auto wlan0
iface wlan0 inet dhcp
wpa-conf /home/long/wifi.conf
>> sudo reboot

注意

路由器必须要打开DHCP才可以正常连接。

最简化的Android入门程序

用Android Studio创建的空项目包含好几个文件夹和文件,最核心的文件其实只有三个:

  1. manifests目录下的AndroidManifest.xml
  2. java目录下的MainActivity.java
  3. layout目录下的activity_main.xml

以下是一个最简单的Android程序,启动后是一个空的页面。

  1. AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.along.homebank">

    <application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

最关键的是 <intent-filter> 部分,里面设置了MainActivity是默认启动的Activity。

  1. MainActivity.java
package com.example.along.homebank;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

最关键的是 setContentView(R.layout.activity_main); ,里面设置了程序创建时要渲染的layout,也就是界面。

  1. activity_main.xml
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.along.homebank.MainActivity">
</android.support.design.widget.CoordinatorLayout>

这个布局文件基本是空的,因为我们什么都没有放进去,所以程序运行时是一个白屏。

从这个最基本的Android程序中,我们可以看到一种程序设计的通用模式:"配置+逻辑+布局"。 配置负责控制一些全局的东西,逻辑负责控制整个程序的逻辑实现,布局负责控制用户交互。 就好比做网站,一些JavaScript文件负责配置,大部分JavaScript负责逻辑,HTML和CSS负责布局。 再经过合理的连接,形成配合,共同完成任务。不得不说,有一种程序设计上的"秩序美"。 而这种有秩序的紧密配合,在程序开发中处处可见。 也许这种美就是"自顶向下,逐步求精"和"模块化"两大思想的最好体现。

Python判断网络连接是否正常

def checkconnection():
    proxies = {"http": "http://192.168.1.254:8228", "https": "http://192.168.1.254:8228"}
    try:
        r1 = requests.get("http://www.facebook.com",
                          proxies=proxies,
                          timeout=5)
        if str(r1.status_code) == "200":
            return True
        return False
    except Exception as e:
        return False

注意

如果不需要测试代理,去掉 proxies=proxies, 就可以了。