Vala для Java разработчиков

Это любительский перевод. Что не знал как перевести - оставил как было.

Contents

  1. Vala для Java разработчиков
    1. Исходные файлы
    2. Компиляция
    3. Использование библиотек
    4. Соглашения об именовании
    5. Организация кода
    6. Главная точка входа
    7. Базовые типы
    8. Строки
    9. Массивы
    10. Вывод типов
    11. Foreach
    12. Наследование
    13. Базовый класс Object
    14. Перегрузка методов
    15. Множественные конструкторы
    16. Цепочка конструкторов
    17. Перезапись
    18. Модификаторы доступа
    19. Интерфейсы
    20. Перечисления
    21. Информация о типах во время выполнения
    22. Уничтожение объектов
    23. Аннотации
    24. Свойства
    25. Делегаты, замыкания
    26. Уведомления
    27. Уведомление об изменении свойств
    28. Исключения
    29. Изменяемые параметры
    30. Проверка на NULL
    31. Проверка аргументов
    32. Стуктуры
    33. Синхронизация
    34. Условная компиляция
    35. Управление памятью
    36. Статическая инициализация
    37. Переменное число аргументов
    38. Нативные методы
    39. Не доступны
    40. Фичи, не освещенные в этом туториале
    41. Коллекции
    42. Ввод-вывод, сетевые сокеты
    43. Консольный Ввод/Вывод
    44. От Swing к GTK+
      1. Простое GUI приложение
      2. Таблица соответствий

Исходные файлы

Java: *.java

Vala: *.vala

Компиляция

Java: компилируется в байт-код (файлы .class)

$ javac SourceFile1.java SourceFile2.java

Vala: компилируется в родной код, используя С как промежуточный.

$ valac source1.vala source2.vala -o program

Стандартной объектной системой Vala является GObject, скомпилированные Vala библиотеки являются валидными С библиотеками.

Использование библиотек

Java: .jar файлы

$ javac -classpath foo-1.0.jar;bar-3.0.jar SourceFile.java

Vala: пакеты (C библиотеки с .vapi файлами)

$ valac --pkg foo-1.0 --pkg bar-3.0 source.vala

Соглашения об именовании

Java

  • классы, интерфейсы, перечисления: CamelCase

  • методы, локальные переменные, поля: mixedCamelCase

  • константы, значения перечислений: UPPER_CASE

Vala

  • classes, interfaces, structs, enums, delegate types, namespaces: CamelCase

  • methods, local variables, fields, properties, signals: lower_case

  • constants, enum values: UPPER_CASE

No non-ASCII letters for identifiers allowed. You can use Vala keywords as identifiers if you prefix them with @. The at sign is not considered as part of the name.

Организация кода

Файлы

Java: один главный класс на файл, имя файла напоминает имя класса.

Vala: файл может иметь много классов, имя класса не обазяно напоминать имя класса.

Иерархия

Java: пакеты, представленные иерархией директорий, используется reverse domain name scheme

import javax.swing.*;

package org.foo.bar;

// ...

Vala: пространства имен, не связанные с иерархией директорией, никакой reverse domain name scheme

using Gtk;

namespace Foo.Bar {
    // ...
}

Пространства имен Vala могу содержать методы без классов. Они неявно являются static.

Дефолтный импорт

Java: пакет java.lang.* импортируется по умолчанию.

Vala: пространство имен GLib импортируется по умолчанию.

Главная точка входа

Java: public static void main(String[] args)

Vala: static int main (string[] args)

Может быть вне класса, может быть private, может возвращать int (код завершения), аргумент args опциональный.

Базовые типы

  • размеры стандартных типов (int, long, ...) архитиктурно зависимы. Получение размера в байтах осуществляется с помощью sizeof (), например sizeof (int)

  • дополнительные Vala типы int8, int16, int32, int64 (signed), uint8, uint16, uint32, uint64 (беззнаковый) с гарантией архитиктурной независимости размера.

  • нету byte (используйте uint8, int8 вместо него)

  • bool instead of boolean

  • дополнительный базовый тип: unichar, олицетворяющий Unicode символ.

Модификатор константы: const вместо final.

Базовые типы Vala имеют следующие методы:

int a = -4.abs ();
string s = a.to_string ();
int b = int.max (5, 7);      // static method call on 'int'

Строки

Java

Тип данных: String

Проверка на равенство: str1.equals(str2)

Vala

Тип данных: string (нижний регистр)

Проверка на равенство: str1 == str2

Проводится сравнение содержания, а не ссылок. Вы можете сравнивать строки лексикографически с помощью <, >, <=, >= и тд. Строки могут быть использованы с switch.

Строки Vala кодированы в UTF-8.

Дополнительные фичи строк Vala

Vala поддерживает дословыне строки: """..."""

string verbatim = """Verbatim strings don't evaluate escape sequences
like \n, \t, ... and may span multiple lines. The line breaks are part
of the string. You can use quotation marks (") and backslashes (\)
inside a verbatim string without escaping them."""

Vala поддерживают интерполяцию (строковые шаблоны) @"...". Строковые шаблоны могут содержать выражения, но нужно писать доллар $ перед ними.

string name = "John";
stdout.printf (@"Welcome, $name!");
stdout.printf (@"3 + 2 = $(3 + 2)");

Массивы

Динамический рост

Вы можете добавлять элементы к массиву динамически, используя оператор +=.

The array will be reallocated with sizes of powers of two:

int[] squares = {};
for (int i = 0; i < 100; i++) {
    squares += 2 * i;
}

Отсутствие проверки границ

Однако, в Vala отсутствует проверка на выход за пределы массива во время выполнения:

int[] a = new int[10];
a[20] = 1;  // not safe!

(Опциональная проверка планируется в будущих версиях Vala).

Массивы большой размерности

Java: зубчатые массивы большой размерности [][] (массивы массивов) То есть внутренние массивы могу быть не обазательно равной длинны (зазубренные)

int[][] matrix = new int[3][];
for (int[] row : matrix) {
    row = new int[4];
}

Vala: прямоугольные массивы большой размерности [,], [,,], и тд. (размещаются как один смежный блок), поддержка зубчатых массивов планируется

int[,] matrix = new int[3,4];

Иллюстрация: прямоугольные vs. зубчатые массивы больших размерностей

multidimensional-arrays.png

Вывод типов

Vala поддерживает механизм под названием вывод типов (неявная типизация) для локальных переменных: Локальные переменные могут быть объявлены с использованием ключевого слова 'var' вместо типа, если компилятор может вывести (сделать вывод) тип из инициизирующего аргумента. Это помогает избегать ненужной избыточности и особенно полезно для общих типов. Примерчики:

var obj = new Object ();
var map = new HashMap<string, int> ();
var str = "hello, world";
var arr = new int[10];

вместо

Object obj = new Object ();
HashMap<string, int> map = new HashMap<string, int> ();
string str = "hello, world";
int[] arr = new int[10];

А ведь всё еще статически типизированы...

Foreach

Java: for (int i : numbers) { }

Vala: foreach (int i in numbers) { }

Наследование

Java: extends, implements

public class Demo extends Foo implements Bar {
    public Demo() {
        super();
    }
}

Vala: двоеточие и следующие за ним разделенный запятыми список, одинаково для суперклассов и интерфейсов. colon followed by comma separated list, both for super class and interfaces

public class Demo : Foo, Bar {
    public Demo () {
        base ();
    }
}

super называется base (базовый) в Vala.

Базовый класс Object

Java: implicit inheritance from Object (java.lang.Object)

public class Foo {
    // ...
}

Vala: никакого неявного наследования от Object (GLib.Object)

public class Foo : Object {
    // ...
}

Что случится, если не наследовать Object? Да ничего страшного. Эти классы будут чуть более легкие, однако, они не будут иметь таких фич как уведомление об изменении свойства, и выши объекты не будут иметь общего базового класса. Обычно наследование от Object - это то, чего вы хотите (но пока не подозреваете об этом).

Перегрузка методов

Java

public class Demo {

    public void draw(String text) { }

    public void draw(Shape shape) { }


    /* Method overloading + chaining for convenience methods with less arguments */

    void f(int x, String s, double z) { }

    void f(int x, String s) {
        f(x, s, 0.5);
    }

    void f(int x) {
        f(x, "hello");
    }
}

Vala: никакой перегрузки методов, используйте разные имена вместо этого или аргументы по умолчанию.

public class Demo : Object {

    public void draw_text (string text) {
    }

    public void draw_shape (Shape shape) {
    }

    /* Method with argument default values */
    void f (int x, string s = "hello", double z = 0.5) {
    }
}

Vala не поддерживает перегрузку методов потому что библиотеки, написанные на Vala предназначены для исопльзования С программистами, да еще и с осмысленными именами функций.

Множественные конструкторы

Java: перегрузка конструктора

public class Foo {
    public Foo() { }
    public Foo(int foo) { }
    public Foo(String bar) { }
}

new Foo();
new Foo(42);
new Foo("hello");

Vala: именованные конструкторы вместо перегрузки.

public class Foo : Object {
    public Foo () { }
    public Foo.with_foo (int foo) { }
    public Foo.from_bar (string bar) { }
}

new Foo ();
new Foo.with_foo (42);
new Foo.from_bar ("hello");

Цепочка конструкторов

Java: this()

class Foo {
    public Foo() {
        this("bar");
    }

    public Foo(string bar) {
    }
}

Vala: this() или this.name_addition()

class Foo : Object {
    public Foo () {
        this.with_bar ("bar");
    }

    public Foo.with_bar (string bar) {
    }
}

Перезапись

Java: все методы виртуальные (перезаписываемые) по умолчанию, final предотвращает перезапись.

public class Super {
    public int myMethod(int x, int y) { }
    public final void anotherMethod() { }
}

public class Sub extends Super {
    @Override
    public int myMethod(int x, int y) {
        super.myMethod(x, y);
        // ...
    }
}

Vala: все методы не виртуальные по умолчанию, перезапись должна быть явно указана словом virtual. Так что наоборот, Vala имеет ключевого слова override вместо @Override аннотации, и это не опционально.

public class Super : Object {
    public virtual int my_method (int x, int y) { }
    public void another_method () { }
}

public class Sub : Super {
    public override int my_method (int x, int y) {
        base.my_method (x, y);
        // ...
    }
}

Модификаторы доступа

Java

Vala

public

public

protected

protected

package-private (default)

internal

private

private (default)

Хотя по умолчанию все private, вы можете использовать его явно из соображений симметрии к public.

Интерфейсы

Java: методы интерфейсов неявно абстрактные

public interface Foo {
    public void foo(int i);
    public int bar(String s, double d);
}

Vala: нужно указывать abstract явно

public interface Foo {
    public abstract void foo (int i);
    public abstract int bar (string s, double d);
}

Почему: Потому что Vala интерфейсы могут иметь не абстрактные (то есть методы с реализацией)! Это значит, что интерфейсы Vala могут быть использованы как миксины(ограниченная форма множественного наследования).

Vala интерфейсы могуть иметь static методы, например, фабричные методы.

Java: наследование интерфейса

public interface IfaceA {
    public void methodA();
}

public interface IfaceB extends IfaceA {
    public void methodB();
}

public class Demo implements IfaceB {
    public void methodA() { }
    public void methodB() { }
}

Vala: предпосылка интерфейса

interface IfaceA : Object {
    public abstract void method_a ();
}

interface IfaceB : Object, IfaceA {
    public abstract void method_b ();
}

class Demo : Object, IfaceA, IfaceB {
    public void method_a () { }
    public void method_b () { }
}

Интерфейсы в Vala могут не наследоваться от других интерфейсов, но могут объявлять другие интерфейсы как зависимости, которые работают таким же способом. Интерфейсы могут также иметь классы как зависимости. Это часто используется для уверенности в том, что объект интерфейса так же является потомком Object. Факт, что интерфейсы не могут наследоваться от других интерфейсов обусловлен техническими различиями - на практике Vala система работает так жк как Java в этой области, но с экстра фичами зависимости классов.

Перечисления

Java: перечисления основаны на классов

Vala: перечисления основаны на целых. Методы разрешены, однако никаких конструкторов, полей, и тд.

enum Season {
    SPRING,
    SUMMER,
    AUTUMN,
    WINTER;

    public bool is_hot () {
        return this == SUMMER;
    }
}

Информация о типах во время выполнения

Динамическая проверка типов

Java: obj instanceof Foo

Vala: obj is Foo

Динамическое приведения типов

Java: Foo foo = (obj instanceof Foo) ? (Foo) obj : null

Vala: Foo foo = obj as Foo

Конечно, "(obj is Foo) ? (Foo) obj : null" будет также работать.

Получения информации от типов

Java

Class c = Foo.class;
System.out.println(c.getName());
Foo = (Foo) c.newInstance();

Vala: оператор typeof ()

Type t = typeof (Foo);
stdout.printf ("%s\n", t.name ());
Foo o = (Foo) Object.new (t);

Уничтожение объектов

Java: finalizer'ы, не детерминированные

public class Foo {
    @Override
    protected void finalize() {
    }
}

Vala: дестркторы, детерминированные

public class Foo : Object {
    ~Foo () {
    }
}

Аннотации

Java: @Annotations, самоопределяемые

Vala: attributes, built into the compiler. Syntax: [AttributeName (param1 = value, param2 = value)]. Mostly used for bindings or D-Bus interfaces. The most prominent attribute for bindings is [CCode (...)]

Свойства

Java: соглашение Bean, методы getX() и setX()

public class Person {
    private int age = 32;

    public int getAge() {
        return this.age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public static void main(String[] args) {
        Person p = new Person();
        p.setAge(p.getAge() + 1);
    }
}

Vala: поддержка языком для свойств блоков get {} и set {}, могуть быть доступны как поля

public class Person : Object {
    private int _age = 32;

    public int age {
        get { return _age; }
        set { _age = value; }
    }
}

void main () {
    var p = new Person ();
    p.age++;
}

Иди даже короче для стандартной реализации:

public class Person : Object {
    public int age { get; set; default = 32; }
}

Делегаты, замыкания

Java: реализовывайте сами, используя анонимные внутренние классы

public interface MyDelegateType {
    public void invoke(int a, double b);
}

public class Demo {
    private static void foo(MyDelegateType deleg) {
        deleg.invoke(32, 0.25);
    }

    public static void main(String[] args) {
        MyDelegateType deleg = new MyDelegateType () {
            public void invoke(int a, double b) {
                System.out.println("a = " + a + "; b = " + b);
            }
        };
        deleg.invoke(42, 0.75);
        foo(deleg);
    }
}

Vala: языковая поддержка для делегатов и замыканий

delegate void MyDelegateType (int a, double b);

void foo (MyDelegateType deleg) {
    deleg (32, 0.25);     // invoke delegate
}

void main () {
    MyDelegateType deleg = (a, b) => {
        stdout.printf ("a = %d; b = %g\n", a, b);
    };
    deleg (42, 0.75);     // invoke delegate
    foo (deleg);          // pass delegate to a method
}

Замыкания - это анонимные методы, которые захватывают переменные из внешней области видимости. Они могут быть присвоены переменыным делегатам или могут быть переданы в методы как делегаты.

В Java замыкания могут симулироваться с помощью анонимных вложенных классов. Однако анонимыные вложенные классы могут захватывать только final переменные с внешней области видимости, в то время как Vala замыкания могут захватывать любую переменную. Поддержка замыканий планируется в Java 7.

Вы можете присваивать методы прямо делегатным переменным:

delegate int MyDelegateType (int a, double b);

int add (int a, int b) {
    return a + b;
}

int sub (int a, int b) {
    return a - b;
}

void main () {
    MyDelegateType deleg = add;
    int sum = deleg (2, 3);
    deleg = sub;
    int diff = deleg (8, 4);
}

Это значит, что методы могут размещаться в переменных и могут передаваться как объекты.

Уведомления

Java: листенеры (реализуйте observer pattern)

public interface ClickListener {
    public void clicked(Clickable source);
}

public interface Clickable {
    public void addClickListener(ClickListener l);
    public void removeClickListener(ClickListener l);
}

public class MyButton implements Clickable {
    private List<ClickListener> clickListeners;

    public MyButton() {
        this.clickListeners = new ArrayList<ClickListener>();
    }

    private void fireClickListeners() {
        for (ClickListener listener : this.clickListeners) {
            listener.clicked(this);
        }
    }

    public void addClickListener(ClickListener l) {
        if (l != null) {
            this.listeners.add(l);
        }
    }

    public void removeClickListener(ClickListener l) {
        if (l != null) {
            this.listeners.remove(l);
        }
    }

    public void test() {
        fireClickListeners();    // fire listeners
    }
}

public class Demo {

    private class MyClickListener implements ClickListener {
        public void clicked(Clickable s) {
            System.out.println("handler C");
        }
    }

    public static void main(String[] args) {
        MyButton b = new MyButton();
        b.addClickListener(new ClickListener() {
            public void clicked(Clickable s) {
                System.out.println("handler A");
            }
        });
        b.addClickListener(new ClickListener() {
            public void clicked(Clickable s) {
                System.out.println("handler B");
            }
        });
        MyClickListener handlerC = new MyClickListener();
        b.addClickListener(handlerC);
        b.test();
        b.removeClickListener(handlerC);
    }
}

Vala: сигналы (ключевые слова signal, .connect() и .disconnect())

public class MyButton : Object {

    public signal void clicked ();

    public void test () {
        clicked ();          // emit signal
    }
}

void handler_c (MyButton source) {
    stdout.printf ("handler C\n");
}

void main () {
    var b = new MyButton ();
    b.clicked.connect ((s) => stdout.printf ("handler A\n"));
    b.clicked.connect ((s) => {
        stdout.printf ("handler B\n");
    });
    b.clicked.connect (handler_c);
    b.test ();
    b.clicked.disconnect (handler_c);
}

Уведомление об изменении свойств

Java

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class DemoBean {

    private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
    private String title;

    public String getTitle() {
        return this.title;
    }

    public void setTitle(String title) {
        String old = this.title;
        this.title = title;
        this.pcs.firePropertyChange("title", old, title);
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        this.pcs.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        this.pcs.removePropertyChangeListener(listener);
    }

    public static void main(String[] args) {
        DemoBean demo = new DemoBean();
        demo.addPropertyChangeListener(new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent evt) {
                System.out.println("Property " + evt.getPropertyName() + " changed");
            }
        });
        demo.setTitle("hello");
        demo.setTitle("world");
    }
}

Vala: подклассы Object имеют сигнал notify

public class Demo : Object {
    public string title { get; set; }
}

void main () {
    var demo = new Demo ();
    demo.notify.connect ((s, p) => stdout.printf ("Property %s changed\n", p.name));
    demo.title = "hello";
    demo.title = "world";
}

Однако вы н можете получить старое значение.

Если вы интересуетесь уведомлением об изменении единственного свойства, вы можете использовать такой синтаксис:

demo.notify["title"].connect ((s, p) => stdout.printf ("title changed\n"));

Уведомление может быть отключено с помощью CCode атрибута мгновенно до объявления свойства:

class MyObject : Object {

    // notify signal is NOT emitted upon changes in the property
    [CCode (notify = false)]
    public int without_notification { get; set; }

    // notify signal is emitted upon changes in the property
    public int with_notification { get; set; }
}

Исключения

Java: основанные на классах исключения

public class TemperatureException extends Exception {
}

public class TooColdException extends TemperatureException {
}

public class TooHotException extends TemperatureException {
}

public class ExceptionDemo {
    private void method() throws TemperatureException {
        throw new TooColdException("It's too cold!");
    }

    public static void main(String[] args) {
        try {
            method();
        } catch (TemperatureException e) {
            System.out.println(e.getMessage());
        }
    }
}

Vala: исключения называются ошибки, не основаны на классах, никаких оберток

// error domain with multiple error codes instead of exception classes
errordomain TemperatureError {
    TOO_HOT,
    TOO_COLD
}

void method () throws TemperatureError {
    // error domain, error code, error message
    throw new TemperatureError.TOO_COLD ("It's too cold!");
}

// must be caught or propagated, compiler warning if ignored
try {
    method ();
} catch (TemperatureError e) {
    stderr.printf ("Error: %s\n", e.message);
}

Хотя может компилятор излучает предупреждения для игнорируемых ошибок он не прерывает компиляцию. Он разрешает прототипирования без необходимости обработки ошибок и мы надеемся, что предотвратит множество забытых пустых catch блоков.

Вы можете проверять код ошибки с помощью is:

    if (e is TemperatureError.TOO_COLD) {
        // ...
    }

Изменяемые параметры

Vala методы могут иметь так называемые out и ref аргументы. Если аргумент метода помечен как out или ref в сигнатуре метода, это значит, что метод может изменять значения переданной переменной (тольо переменные могут быть переданны как out или ref аргументы) и изменения останутся после выполнения метода. Если передана переменная не ссылочного типа, метод может тупо поменять ссылку (взять и прибавить новый объект переменной вместо изменения состояния переданного объекта).

Различие между out и ref в том, что переменная переданная как ref аргумент обязана быть инициализирована до передачи в метод, в то время как переменная, переданная как out может быть инициализирована и ожидается быть инициализированной методом.

Ключевые слова обязаны сразу использоваться и при определении, и при вызове метода.

/*
 * This method takes a normal argument, an 'out' argument
 * and a 'ref' argument.
 */
void my_method (int a, out int b, ref int c) {
    a = 20;  // will have no effect outside of this method

    // until now 'b' is considered uninitialized
    b = 30;  // initialize 'b', will affect the passed variable

    c = 40;  // will affect the passed variable
}

void main () {
    int x = 2
    int y;      // may be uninitialized
    int z = 4;  // must be initialized before it is passed as 'ref' argument
    my_method (x, out y, ref z);
    stdout.printf ("%d %d %d\n", x, y, z);  // => "2 30 40"
    // 'x' is still the same, 'y' and 'z' have changed
}

Проверка на NULL

В Vala вы обязаны помечать параметры методов ссылочного типа как НУЛЛевые с вопросительным знаком (?) если вам нужна возможность передавать null, например:

void my_method (Object? a, Object b) { }

void main () {
    my_method (null, new Object());  // allowed (first argument may be null)
    my_method (null, null);          // not allowed (second argument must not be null)
}

Проверка идет на этапе выполнения и частично на этапе компиляции. Это помогает предотвратить разыменование null указателя.

Вы можете включить (экспериментальная фича) строгую проверку на null опцией --enable-experimental-non-null. Затем Vala проверяет все переменные ссылочного типа во время компиляции, не только методы аргументов. Например, этот пример не скомпилируется со строгой проверкой на null:

void main () {
    string? a = "hello";
    string b = a;        // Error: 'a' could be null and 'b' is not nullable
}

However, if you cast the nullable variable into a non-nullable variable with (!) it will compile:

void main () {
    string? a = "hello";
    string b = (!) a;
}

There are experiments with non-null types (via @NonNull annotations) for Java as well, e.g. JACK and JastAdd

Проверка аргументов

Java

void method(double d, int i, Foo foo) {
    if (d < 0 || d > 1.0)
        throw new IllegalArgumentException();
    if (i < 0 || i > 10)
        throw new IllegalArgumentException();
    if (foo == null)
        throw new IllegalArgumentException();
    // ...
}

Vala: параметры ссылочного типа неявно проверяются на null если они не помечены НУЛЛевыми с помощью ?, так что вам не нужно проверять их вручную. Методы могут иметь преусловия:

void method (double d, int i, Foo foo)
     requires (d >= 0.0 && d <= 1.0)
     requires (i >= 0 && i <= 10)
{
    // ...
}

Vala дополнительно поддерживает преусловния, например для проверки возвращающих значений:

int square (int i)
    ensures (result >= 0)
{
    return i * i;
}

result - специальная переменная, олицетворяющая возвращаемое значение.

Используйте исключения (ошибки) для восстанавливаемых ошибок выполнения (ошибки баз данных, ввода/вывода), используйте преусловия и ассерты (assert (...)) для программирования ошибок таких как неверные аргументы.

Стуктуры

Концепция структур недоступна в Java. Для понимания различий между структурой и классом мы взглянем на две реализации типа Point, одну как класс и другую как струтруру.

class Point {
    public int x;
    public int y;

    public Point (int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void print () {
        stdout.printf ("(%d, %d)", this.x, this.y);
    }
}

struct Point {
    public int x;
    public int y;

    public Point (int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void print () {
        stdout.printf ("(%d, %d)", this.x, this.y);
    }
}

Как вы видите, единственным различием является ключевое слово struct вместо class. Однако структурные типы имеют разные семантические отличия от классов:

// Class
var p1 = new Point (2, 4);  // will allocate p1 on the heap
var p2 = p1;                // assignment by reference
p2.x = 3;
p1.print ();                // => (3, 4)   p1 changed as well
p2.print ();                // => (3, 4)
var p3 = new Point (3, 4);
p2 == p3;                   // => false (same values, but different references)

// Struct
var p1 = Point (2, 4);      // will allocate p1 on the stack
var p2 = p1;                // copied
p2.x = 3;
p1.print ();                // => (2, 4)   p1 did not change
p2.print ();                // => (3, 4)
var p3 = Point (3, 4);
p2 == p3;                   // => true (same values)

Структуры не размещаются в памяти (вот почему ключевое слово new не используется для создания структур). Самое важное различие - это то, что структуры копируются при присваивании. Это value-тип, не ссылочный, то есть в общем они ведут себя как int, double, и тд.

Структуры не поддерживают наследование и сигналы, они не могут реализовывать интерфейсы.

Синхронизация

Java: synchronized

Vala: lock (блокировочки), могут быть применены к целым методам, только к членам объектов.

Условная компиляция

Java: да нету ее там

Vala: поддержка простой условной компиляции: #if, #elif, #else, #endif. Однако это не макрос препроцессора как С препроцессор.

Смотрите Conditional Compilation Example

Управление памятью

Java: Сборщик мусора

Vala: Автоматический подсчет ссылок

Они оба имеютпреимущества и недостатки. Подсчет ссылок является детерминистическим, но вы можете генерировать цликлические ссылки с некоторых случаях. В этих случаях вы обязаны использовать слабые сслыки для предотвращения зацикливания. Ключевое слово в Vala для этого weak.

Читайте рассказ об управлению памятью в Vala

Статическая инициализация

Java: статический блок инициализатор, вызываемый до создания первого объекта или любого обращения к статическим членам

public class Foo {
    static {
        System.out.println("Static initializer block invoked.");
    }
}

Vala: блок static construct { }. В первый раз, когда класс, или любой потомок инстанцируется (создается объект), этот код выполняется. Это гарантирует, что код будет запущен в точности один раз в программе, где данный класс используется.

class Foo : Object {
    static construct {
        stdout.printf ("Static constructor invoked.\n");
    }
}

Дополнительно Vala класс может иметь class construct { } блок. Этот блок будет выполнен однажды при первом использовании этого класса, и однажды при первом использовании каждого потомка этого класса.

Переменное число аргументов

Java:

String format(String pattern, Object... arguments) {
    // ...
}

Vala: в стиле С, не типобезопасно.

string format (string pattern, ...) {
    var l = va_list ();
    // ...
}

Для большей информации, смотрите общий Vala Tutorial. Типобезопасные аргументы планируются планируются с помощью ключевого слова params.

Нативные методы

Java: ключевое слово native, JNI

Vala: все вызовы методов являются нативными методами. Свяжите С функции быстро с помощью ключевого слова extern или напишите '.vapi' файл. Используйте CCode стрибут для указаняи оригинального имя функции (только если отличается от Vala имени)

public class MainClass : Object {

    [CCode (cname = "SampleMethod")]
    public static extern int sample_method (int x);

    static void main () {
        stdout.printf ("sample_method () returns %d\n", sample_method (5));
    }
}

Передайте имя библиотеки компилятору с помощью -X -l... (-X имеет в виду следующую опцию, проброшенную в С компилятор)

$ valac demo.vala -X -lfoo

Вы можете также передать исходный С файл, содержащий external методы в Vala компилятор. Это позволяет смешивать Vala и C исходный код в проекте.

$ valac demo.vala foo.c

Не доступны

  • Нет final классов (планируется как seaked классы)

  • Нет статических классов (используйте вложенные пространства имен вместо этого)
  • Нет анонимных вложенных классов (используйте делегаты + замыкания вместо этого)
  • Нет ограничений на параметры универсального типа
  • Нет нявного преобразования объектов в строки (нет общего toString()). Однако типы, которые имеют метод to_string() поддерживаются строковыми шаблонами (@"...")

  • Нет именованных breaks / labels
  • Нет ключевых слов strictfp, transient

Фичи, не освещенные в этом туториале

  • Асинхронные методы
  • Alternative construction scheme (gobject-style)

Смотрите общий Vala туториал для большей информации.

Коллекции

Java: пакет java.util.*

Vala: пространство имен Gee, --pkg gee-1.0, http://live.gnome.org/Libgee

Смотрите Gee Examples, Gee Documentation

Vala разрешает массиво-подобный синтаксис для Gee коллекций (например my_map[key] является эквивалентом my_map.get(key). Vala поддерживает оператор in для коллекций: x in my_collection is equivalent to `my_collection.contains (x). Этот оператор также работает со строками даже не смотря на то, что строки не являются коллекциями.

Пожалуйста, заметьте что Libgee делает проверку на ошибки типа выхода за границы для ключа с помощью assert, так что это не возбуждает никакого ловимого исключения RuntimeException как делает Java.

Ввод-вывод, сетевые сокеты

Java: пакеты java.io.*, java.net.*

Vala: пространство имен GLib (импортируется по умолчанию), --pkg gio-2.0, GIO является частью GLib

Смотрите GIO Examples, GIO Networking Examples

Консольный Ввод/Вывод

Java

System.out.println("Hi!");
System.out.print("Please enter your name: ");
String name = System.console().readLine();
System.out.format("Welcome, %s!\n", name);

Scanner stdin = new Scanner(System.in);
System.out.print("Enter a string, a double, a float, and an int: ");
String s = stdin.next();
double d = stdin.nextDouble();
float f = stdin.nextFloat();
int i = stdin.nextInt();

System.out.println("You entered the following:");
System.out.println("String : " + s);
System.out.println("double : " + d);
System.out.println("float  : " + f);
System.out.println("int    : " + i);

Vala

stdout.printf ("Hi!\n");
stdout.printf ("Please enter your name: ");
var name = stdin.read_line ();
stdout.printf ("Welcome, %s!\n", name);

string s;
double d;
float f;
int i;
stdout.printf ("Enter a string, a double, a float, and an int: ");
stdin.scanf ("%s", out s);
stdin.scanf ("%lf", out d);
stdin.scanf ("%f", out f);
stdin.scanf ("%d", out i);

stdout.printf ("You entered the following:\n");
stdout.printf ("string : %s\n", s);
stdout.printf ("double : %lf\n", d);
stdout.printf ("float  : %f\n", f);
stdout.printf ("int    : %d\n", i);

От Swing к GTK+

Простое GUI приложение

Java

import javax.swing.*;

public class HelloWorldFrame extends JFrame {

    public HelloWorldFrame() {
        JLabel label = new JLabel("Hello World");
        add(label);
        setSize(100, 100);
    }

    public static void main(String args[]) {
        JFrame frame = new HelloWorldFrame();
        frame.setVisible(true);
    }
}

Vala

using Gtk;

public class HelloWorldWindow : Window {

    public HelloWorldWindow () {
        var label = new Label ("Hello World");
        add (label);
        set_default_size (100, 100);
    }
}

void main (string[] args) {
    Gtk.init (ref args);

    var win = new HelloWorldWindow ();
    win.show_all ();

    Gtk.main ();
}

Обязаны компилировать с --pkg gtk+-3.0

Смотрите GTK+ Examples

Таблица соответствий

Swing

GTK+

JButton

Button

JCheckBox

CheckButton

JColorChooser

ColorSelection

JComboBox

ComboBox

JComponent

Widget

JDialog

Dialog

JEditorPane

TextView

JFileChooser

FileChooserDialog

JFrame

Window

JLabel

Label

JList

TreeView with ListStore

JMenu

Menu

JMenuBar

MenuBar

JOptionPane

MessageDialog

JPanel

Container (depending on layout: Box, Table, Fixed, ...)

JPasswordField

Entry with visibility = false

JProgressBar

ProgressBar

JRadioButton

RadioButton

JScrollPane

ScrolledWindow

JSeparator

Separator

JSlider

Scale

JSpinner

SpinButton

JSplitPane

Paned

JTabbedPane

Notebook

JTable

TreeView with ListStore

JTextArea

TextView

JTextField

Entry

JTextPane

TextView

JToolBar

Toolbar

JToolTip

Tooltip

JTree

TreeView with TreeStore

JViewport

Viewport

Projects/Vala/ValaForJavaProgrammers/ru (last edited 2013-11-22 16:48:28 by WilliamJonMcCann)