Java

Примитивные типы

  • byte (8 бит): [-128...127]
  • short (16 бит): [-32768 ... 32767]
  • int (32 бит): [-2147483648 ... 2147483647]
  • long (64 бит): [-9223372036854775808 ... 9223372036854775807]

Примитивные типы

  • char (16 бит): ['\u0000' ... '\uffff']
  • float (32 бит)
  • double (64 бит)
  • boolean: false, true

Числа с плавающей точкой

  • float: точность 24 бита, ~7 знаков после запятой
  • double: точность 53 бита, ~16 знаков после запятой

Числа с плавающей точкой

public class Main {

   public static void main(String[] args)  {

       float f = 0.0f;
       for (int i=1; i <= 7; i++) {
           f += 0.1111111111111111;
       }

       System.out.println(f);
   }
}
Результат: 0.7777778

Числа с плавающей точкой

public class Main {

   public static void main(String[] args)  {

       double f = 0.0f;
       for (int i=1; i <= 7; i++) {
           f += 0.1111111111111111;
       }

       System.out.println(f);
   }
}
Результат: 0.7777777777777779

Числа с плавающей точкой

public class Main {
   public static void main(String[] args)  {
       //прибавляем к нулю 0.1 одиннадцать раз подряд
       double f1 = 0.0;
       for (int i = 1; i <= 11; i++) {
           f1 += .1;
       }

       //Умножаем 0.1 на 11
       double f2 = 0.1 * 11;

       //должно получиться одно и то же - 1.1 в обоих случаях
       System.out.println("f1 = " + f1);
       System.out.println("f2 = " + f2);

       // Проверим!
       if (f1 == f2)
           System.out.println("f1 и f2 равны!");
       else
           System.out.println("f1 и f2 не равны!");
   }
}
f1 = 1.0999999999999999
f2 = 1.1
f1 и f2 не равны!

Числа с плавающей точкой

final double threshold = 0.0001;
if (Math.abs(f1 - f2) < threshold)
    System.out.println("f1 и f2 равны");
else
    System.out.println("f1 и f2 не равны");

ООП

  • Класс
  • Объект класса
  • Поля
  • Методы
  • Наследование
  • Интерфейсы

Класс

public class HelloWorld {
	public static void say(String str) {
		System.out.println(str);
	}

	public static void main(String[] args) {
		say("Hello");
		say("World!");
	}

}

Точка входа, JAR

manifest.mf:
Manifest-version: 1.0
Main-Class: HelloWorld
javac HelloWorld.java
jar cfm hw.jar manifest.mf HelloWorld.class
java -jar hw.jar

Класс Object

  • Все классы наследуются от Object (явно или неявно).
  • toString()
  • hashCode()
  • equals(Object obj)
  • getClass()
  • finalize()

Экземпляр класса

package ru.petrsu.cross;

public class Say {
	public void say(String str) {
		System.out.println(str);
	}
}
import ru.petrsu.cross.Say;

public class HelloWorld {
	
	public void main(String[] args) {
	    Say s = new Say();
	    s.say("Hello");
	    s.say("World!");
	}
}

Экземпляр класса

  • Say располагаем по имени пакета (ru/petrsu/cross)
  • Компилируем Say: javac Say.java
  • Компилируем HelloWorld: javac -cp . HelloWorld.java
  • Запускаем HelloWorld: java -cp . HelloWorld

Модификаторы

  • public
  • private
  • protected

Абстрактный класс

  • abstrac - метод только описан, но не реализован, класс содержит абстрактные методы.
package ru.petrsu.cross;

public class Say {
    public void say(Anymal animal) {
	System.out.println(animal.say());
    }
}

package ru.petrsu.cross;

abstract public class Animal {
    abstract public String say();
}

Абстрактный класс

package ru.petrsu.cross;
public class Dog extends Animal {

    public String say() {
	return "Hav";
    }
}

import ru.petrsu.cross.Say;
import ru.petrsu.cross.Dog;

public class HelloWorld {

	public static void main(String[] args) {
	    Say s = new Say();
	    s.say(new Dog());
	}
}

final

  • Переменная класса final - инициализируется при объявлении или в теле конструктора.
  • public static final - константы, значение не меняется.
  • final метод - нельзя переопределить в классе наследнике
  • final класс - нельзя наследовать.

Другие модификаторы

  • synchronized - метод, для которого осуществляется блокировка доступа к ресурсу
  • transient - переменная не должна быть сериализована
  • native - метод реализован на C или другим платформо-зависимым способом
  • volatile - переменная не должна оптимизироваться

synchronized

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       //...какая-то логика, доступная для всех потоков

       synchronized (obj) {

           //логика, которая одновременно доступна только для одного потока
       }
   }
}

Сериализация.

  • Сохранение/восстановление объектов в/из потока.
  • Встроен в Java машину.
  • Сериализуемый объект должен состоять тоже только из сериализуемых объектов.
  • Интерфейс-маркер – Serializable

Сериализация.

class Dog implements Serializable
{
    public String name;
    public int age;
    public int weight;
}

Сериализация.

public static void main(String[] args) throws Exception
{
    Dog dog = new Dog();

    //save cat to file
    FileOutputStream fileOutput = new FileOutputStream("dog.dat");
    ObjectOutputStream outputStream = new ObjectOutputStream(fileOutput);
    outputStream.writeObject(dog);
    fileOutput.close();
    outputStream.close();

    //load cat from file
    FileInputStream fiStream = new FileInputStream("dog.dat");
    ObjectInputStream objectStream = new ObjectInputStream(fiStream);
    Object object = objectStream.readObject();
    fiStream.close();
    objectStream.close();

    Dog newDog = (Dog)object;
}

transient

class Dog implements Serializable
{
    public String name;
    public int age;
    public int weight;

    transient public InputStream in = System.in;
}

native

  • Java Native Interface (JNI) — стандартный механизм для запуска кода, под управлением виртуальной машины Java (JVM), который написан на языках С/С++ или Ассемблера.
  • Модификатор может быть применен только к методам, но не классам и переменным.
  • Тело нативного метода должно заканчиваться на (;) как в абстрактных методах, идентифицируя то, что реализация опущена.

native

package ru.petrsu.cross;

public class JNIHelloWorld {
    native void printHelloWorld();
}

native

/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
/* Header for class ru_forwolk_test_JNIHelloWorld */

#ifndef _Included_ru_forwolk_test_JNIHelloWorld
#define _Included_ru_forwolk_test_JNIHelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     ru_forwolk_test_JNIHelloWorld
 * Method:    printHelloWorld
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_ru_forwolk_test_JNIHelloWorld_printHelloWorld
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
Генерируется из исходников: javah ru.forwolk.test.JNIHelloWorld

native

#include 
#include "JNIHelloWorld.h"

JNIEXPORT void JNICALL Java_ru_forwolk_test_JNIHelloWorld_printHelloWorld
        (JNIEnv *, jobject) {
    std::cout << "Hello world!";
}
Компиляция: g++ -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" -fPIC JNIHelloWorld.cpp -shared -o helloworld.so -Wl,-soname -Wl,--no-whole-archive

native

package ru.petrsu.cross;

public class JNIHelloWorld {
    native void printHelloWorld();
    static {
        System.load(System.getProperty("PROJECT_ROOT") + "/bin/helloworld.so"); //Absolute path!
    }
}

public static void main(String[] args) {
    JNIHelloWorld p = new JNIHelloWorld();
    p.printHelloWorld();
}

volatile

  • Многопоточное программирование.
  • Атомарно читаться и записываться.
  • Java-машина не будет помещать ее в кэш.
  • Метод yield()

Интерфейсы

  • Прототип класс с методами без реализации.
  • Имплементация методов в классе, который реализует интерфейс.

Интерфейсы

interface Animal {
    public String say();
} 

public class Dog implements Animal {
    public String say() {
	return 'Hav';
    }
} 

Интерфейсы vs абстрактный файл

  • Интерфейс описывает только поведение. У него нет состояния.
  • У абстрактного класса состояние есть: он описывает и то, и другое.
  • Абстрактный класс связывает между собой и объединяет классы, имеющие очень близкую связь.
  • В то же время, один и тот же интерфейс могут реализовать классы, у которых вообще нет ничего общего.
  • Классы могут реализовывать сколько угодно интерфейсов, но наследоваться можно только от одного класса.

Аннотации

  • Метаданные для функции/класса/пакета.
  • Работают на этапе компиляции и в runtime.
  • Отслеживать правильность кода, его анализировать
  • Оптимально для API, библиотек.
  • Стандартные аннотации и пользовательские.

Аннотации

  • SOURCE - аннотации для компилятора
  • CLASS - данные из аннотации будут записаны в байткод но недоступны во время работы. Пишут, что в стандартной библиотеке много аннотаций используют этот вид, и сейчас его держат из-за обратной совместимости. Применяется для очень специфичных задач.
  • RUNTIME - самые популярны, используются во время работы кода.

Source Аннотации

  • Native – переменная под этой аннотацией может ссылаться на нативынй код.
  • SuppressWarnings – подавляет различные предупреждения компилятора.
  • Generated – маркирует исходных код, который был сгенерирован.
  • Override – проверяет переопределение метода.

Source Аннотации

package lombok;

public class Chelovek {
    private String name;
    private int age;

    public Chelovek(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Chelovek() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

Source Аннотации

package lombok;

@Data
public class Chelovek {
    private String name;
    private int age;
}

Библиотека lombok

  • @Getter/@Setter
  • @ToString
  • @EqualsAndHashCode
  • @NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor
  • @Log