Android/Swift vs Java

Swift és un llenguatge de programació multi paradigma enfocat en el desenvolupament d'aplicacions per a iOS, macOS i watchOS. Es possible desenvolupar codi en Swift compatible amb Objective-C, ja que es poden utilitzar les seves llibreries. L'objectiu de Swift és ser un llenguatge segur i de ràpid desenvolupament.


Java és un llenguatge de programació de propòsit general, concurrent, orientat a objectes que va ser dissenyat específicament per tenir tan poques dependències d'implementació com fos possible. La seva intenció és permetre que els desenvolupadors d'aplicacions escriguin el programa una vegada i ho executin en qualsevol dispositiu (conegut en anglès com WORA, o "write onze, run anywhere"), la qual cosa vol dir que el codi que és executat en una plataforma no ha de ser recompilado per córrer en una altra. Java és, a partir de 2012, un dels llenguatges de programació més populars en ús, particularment per a aplicacions de client-servidor de web, amb uns 10 milions d'usuaris reportats.

Història

modifica

Chris Lattner, qui a l'inici de l'any va deixar Apple per començar una nova aventura en Tesla, va començar el seu desenvolupament en el 2010, eventualment va obtenir col·laboració d'altres programadors. Swift es va beneficiar de l'experiència de molts llenguatges prenent idees de Objective-C, Haskell, Rust, Ruby, Python, C#, CLU entre uns altres. Va ser presentat en WWDC 20147 i està dissenyat per integrar-se amb els Frameworks Cocoa i Cocoa Touch (frameworks de desenvolupament d'aplicacions). És un llenguatge de programació ideat per treballar amb les eines que utilitzem actualment per al desenvolupament d'aplicacions. Swift és va pensar com un avanç d'Objective-C però a la keynote d'abans de l'estiu de 2015 és va confirmar una nova versió OpenSource, Swift 2.0. Avui dia és treballa sobre Swift 4.0 que és la que ocupem en aquest article.

El llenguatge de programació Java va ser originalment desenvolupat per James Gosling de Sun Microsystems (la qual va ser adquirida per la companyia Oracle) i publicat en 1995 com un component fonamental de la plataforma Java de Sun Microsystems. La seva sintaxi deriva en gran manera de C i C++, però té menys utilitats de baix nivell que qualsevol d'ells. Les aplicacions de Java són generalment compilades a bytecode (classe Java) que pot executar-se en qualsevol màquina virtual Java (JVM) sense importar l'arquitectura de la computadora subjacent. La companyia Sun va desenvolupar la implementació de referència original per als compiladors de Java, màquines virtuals, i llibreries de classes en 1991 i les va publicar per primera vegada en 1995. A partir de maig de 2007, en compliment amb les especificacions del Procés de la Comunitat Java, Sun va tornar a llicenciar la majoria de les seves tecnologies de Java sota la Llicència Pública General de GNU. Uns altres també han desenvolupat implementacions alternes a aquestes tecnologies de Sun, tals com el Compilador de Java de GNU i el GNU Classpath. El llenguatge Java es va crear amb cinc objectius principals:

  1. Hauria d'usar el paradigma de la programació orientada a objectes.
  2. Hauria de permetre l'execució d'un mateix programa en múltiples sistemes operatius.
  3. Hauria d'incloure per defecte suporti per a treball en xarxa.
  4. Hauria de dissenyar-se per executar codi en sistemes remots de forma segura.
  5. Hauria de ser fàcil d'usar i prendre el millor d'altres llenguatges orientats a objectes, com a C++.

Java és, en la majoria dels casos, un llenguatge interpretat. Què vol dir això? Doncs que un programa especialitzat, l'intèrpret de Java, ha d'anar llegint el codi del programa instrucció a instrucció per descobrir quin és la propera acció a realitzar. Aquesta operació costa molts més cicles de CPU que executar un programa en codi màquina natiu, ja que en aquest últim cas és el propi microprocessador el que s'encarrega de decodificar els instruccions a nivell màquina. Per a això, és compila el codi font escrit en llenguatge Java, per generar un codi conegut com “bytecode” (específicament Java bytecode)—*instruccions màquina simplificades específiques de la plataforma Java. Aquesta peça està “a mig camí” entre el codi font i el codi màquina que entén la dispositiva destinació. El *bytecode és executat llavors en la màquina virtual (*JVM), un programa escrit en codi natiu de la plataforma destinació (que és el que entén el seu maquinari), que interpreta i executa el codi. A més, és subministren biblioteques addicionals per accedir als característiques de cada dispositiu (com els gràfics, execució mitjançant brins o *threads, la interfície de xarxa) de forma unificada. S'ha de tenir present que, encara que hi ha una etapa explícita de compilació, el bytecode generat és interpretat o convertit a instruccions màquina del codi natiu pel compilador JIT.

Swift vs Java

modifica

Llibreries en Swift

modifica

Qualsevol framework de Objective-C o C que suporta mòduls es poden importar directament en Swift. Això inclou tots els sistemes de frameworks de Objective-C com a Fundació, UIKit i SpriteKit-així com biblioteques de C comunes subministrades amb el sistema. Per exemple, per utilitzar les API de Foundation a partir d'un arxiu de Swift, afegiu la següent sentència import al principi de l'arxiu:

import Foundation

Llibreries en Java

modifica
import java.util.*;

Tipus de dades

modifica

Swift és un llenguatge molt tipat, encara que la seva declaració no sempre és necessària gràcies a la seva capacitat d'inferir tipus. Els tipus de dades es divideixen principalment en dos grups. Els Tipus de valor, i els Tipus per referència, es diferencien principalment en com són assignats.

  • En assignar un tipus de valor es guarda una còpia del seu contingut. Es recomana el seu ús quan es requereix copiar la seva informació o es vagi a treballar en múltiples fils.
  • En assignar un Tipus per referència s'assigna una instància compartida que és mutable encara si són usades en constants, és a dir modificar una instància es veurà reflectit en totes les variables i constants que la comparteixin. Es recomana el seu ús quan es requereixi compartir dades mutables.
Variables
modifica

A continuació veurem quines classes genèriques es fan servir en els 2 llenguatges amb uns petits matisos.

En tenim de dues classes:

  • Una variable és un contenidor, el valor del qual pot variar en el transcurs de l'execució del nostre programa.
  • Una constant, per contra, és un valor que romandrà immutable durant tota la seva vida.
Tipus Valor
Int rang des de -2.147.483.648 i 2,147,483,647.
Float número decimal de 32 bits fins a 6 decimals de precisió.
Double coma flotant de 64 bits fins a 15 decimals de precisió.
Bool binari 0 (false) o 1 (true).
String array de caracters.
Char Character en Swift.
Inicialització
modifica
  • Swift
let feina = "DAMO"
let feina: String = "DAMO"
var feina; //Error no existeix valor buit.
var feina: String = "DAMO"
print(feina)
  • Java
String feina;
final String feina = "DAMO"; //constant
System.out.println (feina)

En Swift no fa falta definir el tipus de la variable perquè el compilador té la propietat de determinar per nosaltres quin és el tipus de dada a usar en una variable o constant en funció del seu contingut. Però no poden deixar-se variables buides o sense valor assignat, doncs el valor buit no existeix com a tal.

Podem tenir cadenes de caràcters o Strings:

  • Swift
var nom = "Hola", cognom = "Todos"
var nombreCompleto : String { return nom + " " + cognom }
var nombreCompleto : String = "nom" + " " + "cognom"
  • Java
String nombre = nom + " " + cognom;
Opcionals
modifica

Per defecte Swift no admet valors buits d'inicialització, però sí podem inicialitzar una variable, sense saber qui valor tindrà en aquest moment, però indicant que s'establirà en el futur. Això es fa amb un ‘?’ després del tipus de variable. Per contra, Java no admet opcionals.

  • Swift
var feina: String? = "DAMO" 
print(feina!)

La interrogació indica que la variable és d’un cert tipus, però que encara no volem o no podem assignar-li un valor, per la qual cosa se li assignarà automàticament un valor null i s'emmagatzemarà en un contenidor específic. Quan vulguem recuperar el valor cal afegir el modificador '!' perquè extregui d'aquest contenidor opcional el valor i ho mostri tal qual. És el que es diu un unwrap, desembolcallar o extreure d'un contenidor opcional un valor que podria o no existir al moment que es pregunta per ell.

Controls de flux

modifica
Operadors
modifica
Comparadors Operadors
a ==== b NOT: !a
a != b AND: a && b
a > b OR: a || b
a < b
a >= b
a <= b
Condicionals
modifica
  • Swift
if valid { /*cert*/} else{ /*fals*/ }
  • Java
if (valid) { /*cert*/ }else{ /*fals*/ }
  • Swift
switch valid { case 1:/*cert*/ default: /*defecte*/ }
  • Java
switch (valid) { case 1:/*cert*/ default: /*defecte*/ }
  • Swift

En Swift n'existeixen de diferents tipus:

  1. El bucle for-in realitza un conjunt de sentències per a cada element d'una seqüència.
  2. El bucle for-in realitza un conjunt de sentències per a cada element d'un array/llista.
  3. El bucle for realitza una sèrie de declaracions fins que es compleixi una condició específica, típicament incrementant un comptador cada vegada que el bucle acaba.
  4. El bucle while avalua el seu estat en l'inici de cada passada.
  5. repeat-while, avalua la seva condició al final de cada pas del bucle. Similar a do-while
var llista = [1,2,3,4,5];

for index in 1...5 {
    print("\(index) times 5 is \(index * 5)")
}

for index in llista {
    print("\(index) times 5 is \(index * 5)")
}

for var index = 0; index < 5; ++index {
    print("\(index) times 5 is \(index * 5)")
}

repeat {
    statements
} while condition

while condition {
    statements
}
  • Java
while (expresio) {setencia}
for (index; condicio; index++/index--){sentencia}
for(Demarcacion d: Demarcacion.values()){
	System.out.println(d.toString()+" - ");
}
Propi dels opcionals
modifica
  • Swift
var num: Int?

if let roomCount = num {
    print("John's residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}

En Swift quan fem una sentencia if..else.. podem definir si alhora de comparar el valor se li assigna a una variable nova. Així podem comprovar si és una variable nul·la o no, i alhora reutilitzar-la. En l'exemple anterior podem veure clarament que num conté un valor buit, per tant, en la sentencia s'anirà a l'else.

Mètodes

modifica

Swift integra la característica anomenada String Interpolation que és una manera de crear un nou valor String barrejant variables i qualsevol expressió. Les variables han de ser precedides per una diagonal invertida i envoltada per parèntesi. Pots realitzar qualsevol barreja de tipus de variables. Amb això Apple pretén facilitar l'escriptura i concatenació d'expressions a tipus String i que requeria un major esforç en Objective-C.

var twitterProfileUrl : String { return "https://twitter.com/\(twitterUser)" }

Veiem dos codis que fan el mateix:

public func sayHello(personName: String) -> String {
    let greeting = "Hello, " + personName + "!"
    return greeting
}

public String sayHello(String personName){
    String greeting = "Hello, " + personName + "!";
    return greeting;
}
Diferència
modifica

Fem una mica d'anàlisi del que és cada element:

Tipus Arguments Retorn
Swift func public personame: String String
Java - public String personName String

Tip: func nomes diu al compilar que tractar d'una funció. Tot retorn en Swift va precedit de "->"

Modificadors
modifica

Depenent el nivell de control que es vol oferir a la nostra col·lecció.

Modificador Classe Package Subclasse Tots
public Si Si Si Si
protected SI Si Si No
private Si Si No No
sense especificar Si No No No

En comptes de "protected" Swift implementa "internal".

Múltiples retorns
modifica
func minMax(array: [Int]) -> (min: Int, max: Int) {
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}

Tip: En java NOMÉS es pot retornar un valor. Per accedir a les variables tractarem la funció com un objecte:

let bounds = minMax([8, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)")

var mi_algoritmo: ([Int]) -> (min: Int, max: Int) = minMax
print("min is \(mi_algoritmo([8, -6, 2, 109, 3, 71]).min) and max is \(mi_algoritmo([8, -6, 2, 109, 3, 71]).max)")
Funcions niades
modifica

Funcions niades estan ocultes del món exterior per defecte, però tot i aixó es poden cridar i utilitzar per la seva funció de tancament. Una funció envoltant també pot retornar una de les seves funcions niuades per permetre que la funció niuada pugui ser utilitzada en un altre àmbit d'aplicació.

func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
    func stepForward(input: Int) -> Int { return input + 1 }
    func stepBackward(input: Int) -> Int { return input - 1 }
    return backwards ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(currentValue > 0)

Tip: Depenent de la condició backwards agafarà un dels Int retornat per una de les dues funcions i serà un Int el que retornarà la funció principal. Per tant, l'estructura:

func nom_funcion(arguments: Tipus, ...) -> (Tipus_niades_diferents, ...) -> Tipus_principal {

Necessita fer servir classes internes.

public class Outer {
   static private int CountStatic = 0;
   int CountNonStatic = 0;

   public static class Inner {
      public void doInner() {
         System.out.println( CountStatic );
      }
   }
}

POO (Programació Orientada a Objectes)

modifica

Cada vegada que es defineix una nova classe o estructura, es defineix de manera efectiva un nou tipus.

Classes i estructures
modifica
struct Resolution {
    var width = 0
    var height = 0
}
class VideoMode {
    var resolution = Resolution()
    var interlaced = false
    var frameRate = 0.0
    var name: String?
}

Tip per Swift: Defineix noms perquè coincideixi amb la capitalització dels tipus Swift estàndard (com String, Int i Bool) per a diferenciar-les de variables o mètodes.

Tip per Java: No existeix struct!

  • Les estructures són tipus de valor, mentre que les classes són tipus de referència.
  • A diferència de les classes, es poden crear instàncies de les estructures sense utilitzar un operador new.
  • Les estructures poden declarar constructors, però han d'utilitzar paràmetres.
  • Una estructura no pot heretar d'una altra estructura o classe, ni pot ser la base d'una classe.
  • Una estructura pot implementar interfícies.
Creació
modifica
  • Swift
let someVideoMode = VideoMode()
  • Java
VideoMode someVideoMode = new VideoMode()
Inicializatció
modifica
  • Swift
let vga = Resolution(width: 640, height: 480)
  • Java
Resolution vga = new Resolution(640,480);

En Swift existeixen uns comparadors específics per a comparar classes pròpies.

  • Identical to (=====) vol dir que dues constants o variables de tipus de classe es refereixen exactament a la mateixa instància de classe.
  • Not identical to (!====) vol dir que dos casos són considerats "igual" o "equivalent" al valor, per algun significat apropiat de "igual", segons el definit pel dissenyador del tipus.

Tip per java: Has de crear el mètode de comparació.

En Swift, molts tipus de dades bàsiques com String, Array, i el Diccionari s'implementen com estructures. En aquest cas es copien les dades, com ara cadenes, matrius i diccionaris quan s'assignen a una nova constant o variable, o quan es passen a una funció o mètode.

Herència
modifica

En Swift podem fer servir un inicialitzador de conveniència. Podem crear nous tipus de inicializadors que ens permetin rebre altres paràmetres diferents que els que la classe requereix de per sí, i que ens permetin construir més còmodament la instància.

struct valoresVitales {
  var fuerza: Int
  var vida: Int
}

class Enemigo {
  let nombre: String
  let vital: valoresVitales

  init(nombre: String, vital: valoresVitales) {
    self.nombre = nombre
    self.vital = vital
  }
}

class Orco: Enemigo {
    let clan: String
    
    init(nombre: String, vital: valoresVitales, clan: String) {
        self.clan = clan
        super.init(nombre: nombre, vital: vital)
    }
    
    convenience init (nombre: String, fuerza:Int, vida:Int, clan:String) {
        let vitalOrco = valoresVitales(fuerza: fuerza, vida: vida)
        self.init (nombre: nombre, vital: vitalOrco, clan: clan)
    }
}

//Codi agafat de https://applecoding.com

Un exemple clar on un objecte Orco hereta de la classe Enemigo i apart es fa una extensió de la classe Orco afegint clan. En temps d'execució pots fer una extensió d'una classe, per exemple, que posi la valia del Orco:

extension Enemigo {
    var valia: Int {
        return (self.vital.fuerza * self.vital.vida)
    }
}
//Codi agafat de https://applecoding.com

Senzillament definim una extensió d'Enemic, amb una nova propietat calculada. Una propietat que recupera el valor de força i vida dels valors propis de la classe (self) i torna la multiplicació d'aquests valors. La instància que existeixi d'Orco si accedeix a Orco.valia li retornarà el valor de la nova propietat.

Enumeracions
modifica

Una enumeració defineix un tipus comú d'un grup de valors relacionats i li permet treballar amb aquests valors en una forma de tipus segur dins del seu codi.

enum CompassPoint {
    case North
    case South
    case East
    case West
}

Per accedir-hi:

var directionToHead = CompassPoint.West
//pots accedir-hi més tard amb un punt perquè ja té el punter sobre CompassPoint
directionToHead = .North
public enum CompassPoint { North, South, East, West }

Per accedir-hi

CompassPoint directionToHead = CompassPoint.West;
directionToHead.North;

Extensions

modifica

Les extensions permeten afegir funcionalitats a una class, estructura, enumeració o protocol. Això permet tenir accés a extend types als quals no es té accés al codi font original.

Les extensions de Swift permeten:

  • Afegir propietats computades i propietats de tipus computades
  • Definir instancies de mètodes i tipus de mètodes
  • Proporcionar nous incialitzadors
  • Definir subscripts
  • Definir i utilitzar tipus niats (“anidats”)
  • Convertir un tipus existent a un protocol

Les extensions poden estendre un tipus per i fer que adopti un o més protocols. En cas de voler indicar diversos protocols, la sintaxi seria la següent:

extension SomeType: SomeProtocol, AnotherProtocol {
}

Nota: Si es defineix una extensió per afegir una nova funcionalitat a un type existent, la nova funcionalitat estarà disponible per totes les instàncies d’aquell type, tot i que hagin estat prèviament creades.

Propietats computades
modifica

Les extensions poden afegir propietats computed instance i propietats computed type a tipus existents. En aquest exemple s’afegeixen 5 propietats computed instance al tipus Double, per tal d’afegir suport per treballar amb unitats de distància.

extension Double {
    var km: Double { return self * 1_000.0 }
    var m: Double { return self }
    var cm: Double { return self / 100.0 }
    var mm: Double { return self / 1_000.0 }
    var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm
print("One inch is \(oneInch) meters")
let threeFeet = 3.ft
print("Three feet is \(threeFeet) meters")
Incialitzadors
modifica

Permeten estendre altres tipus els teus propis tipus com a paràmetres d’inicialització a acceptar les pròpies inicialitzacions o afegir inicialitzacions diferents. Es poden afegir nous incialitzadors a una classe, però mai es pot “sobreescriure” l’inicialitzador o el desinialitazdor per defecte de la classe.

extension Rect {
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x: originX, y: originY), size: size)
    }
}
Mètodes
modifica
extension Int {
    func repetitions(task: () -> Void) {
        for _ in 0..<self {
            task()
	    }}}
	    
//Result

3.repetitions({
    print("Hello!")
})

El mètode repetitions(_:) agafa un argument de tipus void (sense paràmetres) i que tampoc retorna cap valor. Després d’afegir aquest mètode es pot cridar repetitions(_:) a qualsevol integer perquè faci una tasca n vegades.

Mutació o modificació de mètodes instance
modifica

Els mètodes afegits amb una extensió poden modificar. Les estructures i mètodes d’enumeració que modifiquen self o les seves propietats han de marcar la instància com a mutating.

El següent exemple afegeix una mutació anomenada square al tipus int que calcula el quadrat del valor original.

extension Int {
    mutating func square() {
        self = self * self
    }
}
var someInt = 3
someInt.square()
Subscripts
modifica

Les extensions poden afegir nous subscripts a un tipus existent.

extension Int {
    subscript(var digitIndex: Int) -> Int {
        var decimalBase = 1
        while digitIndex > 0 {
            decimalBase *= 10
            --digitIndex
        }
        return (self / decimalBase) % 10
    }
}
746381295[0]
// returns 5
746381295[1]
// returns 9
746381295[2]
// returns 2
746381295[8]
// returns 7
Tipus niats
modifica

Les extensions poden afegir tipus niats a les classes, estructures i enumeracions diferents.

extension Int {
    enum Kind {
        case Negative, Zero, Positive
    }
    var kind: Kind {
        switch self {
            case 0:
                return .Zero
            case let x where x > 0:
                return .Positive
            default:
                return .Negative
        }}}
Herència Java
modifica

En Java, la classe que deriva d’una altra classe és anomenada subclass o classe filla, mentre que l'original és anomenada superclass o classe pare.

A diferència de Swift, si es vol modificar el comportament de la classe pare, s’ha de crear una subclass que derivi de la classe pare. D’aquesta forma es poden utilitzar els camps i mètodes (a excepció de la constructora i destructora) de la classe pare, fent una especialització concreta.

Clase pare
modifica
public class Bicycle {
        
    // the Bicycle class has three fields
    public int cadence;
    public int gear;
    public int speed;
        
    // the Bicycle class has one constructor
    public Bicycle(int startCadence, int startSpeed, int startGear) {
        gear = startGear;
        cadence = startCadence;
        speed = startSpeed;
    }
        
    // the Bicycle class has four methods
    public void setCadence(int newValue) {
        cadence = newValue;
    }
        
    public void setGear(int newValue) {
        gear = newValue;
    }
        
    public void applyBrake(int decrement) {
        speed -= decrement;
    }
        
    public void speedUp(int increment) {
        speed += increment;
    }
        
}
Classe filla
modifica
public class MountainBike extends Bicycle {
        
    // the MountainBike subclass adds one field
    public int seatHeight;

    // the MountainBike subclass has one constructor
    public MountainBike(int startHeight,
                        int startCadence,
                        int startSpeed,
                        int startGear) {
        super(startCadence, startSpeed, startGear);
        seatHeight = startHeight;
    }   
        
    // the MountainBike subclass adds one method
    public void setHeight(int newValue) {
        seatHeight = newValue;
    }   
}

Atributs o Anotacions

modifica

Les anotacions són metadata d’un programa que no tenen cap efecte directe. Els seus possible usos sóns els següents:

Funcions
modifica
  • Informar al compilador: Les anotacions poden ser utilitzades pel compilador per detectar errors o evitar warnings.
  • Compile-time and deployment-time processing: Les eines software poden processar la informació de les anotacions per generar codi, com per exemple fitxers XML.
  • Processament en temps d’execució: Algunes anotacions permeten ser utilitzades en temps d’execució.

Per especificar una anotació, s’ha de posar el caràcter ‘@’. Això indica al compilador que és una anotació. Les anotacions poden incloure elements, que poden tenir nom o no, i els seus corresponents valors:

@Author(
   name = "Benjamin Franklin",
   date = "3/27/2003"
)
class MyClass() { ... }

Les anotacions es poden utilitzar en les declaracions de classes, camps, mètodes i altres elements dels programes. Des de la versió de Java SE 8 les anotacions també poden ser aplicades a l’ús de tipus. A continuació alguns exemples:

//Class instance creation expression:
new @Interned MyObject();

//Type cast:
myString = (@NonNull String) str;
implements clause:
class UnmodifiableList<T> implements
        @Readonly List<@Readonly T> { ... }

//Thrown exception declaration:
void monitorTemperature() throws
        @Critical TemperatureException { ... }
Exemples d'anotacions
modifica
  • Java
Annotació Ús
@Deprecated Indica que l’element està desfasat i que no s’hauria d’utilitzar. El compilador genera un warning quan s’utilitza el mètode marcat.
@Override Informa al compilador que l’element sobreescriurà l’element declarat a la superclass.
@SuppressWarnings Indica al compilador que no mostri alguns warnings específics que poden ser generats, com per exemple al utilitzar un mètode deprecated.
@SafeVarargs Quan s’aplica a un mètode o constructor, assegura que el codi no farà cap operació insegura en els vargargs que passa com a paràmetre. Quan s’utilitza aquesta anotació, no es mostren els warnings que estan relacionats amb els varargs.
Anotacions que s’apliquen a altres anotacions. Les més interessants són:
@Documented Indica que en els elements que s’utilitzi l’anotació seran documentats utilitzant l’eina Javadoc tool.
@Target Restringeix quins tipus d’elements s’aplica l’anotació.

 

  • Swift
Annotació Ús
@Available Aquest atribut s’aplica a qualsevol declaració per indicar el cicle de vida relatiu a certes plataformes i versions de sistema operatiu.

Es pot indicar com una llista, de dos o més arguments separats per coma o bé utilitzar l’asterisc (*) oer indicar que està disponible per totes les plataformes que es llisten a continuació.

  • iOS
  • iOSApplicationExtension
  • OSX
  • OSXApplicationExtension
  • watchOS
  • watchOSApplicationExtension
  • tvOS
  • tvOSApplicationExtension
@Unavailable La declaració no està disponible per les plataforma especificades
@Introduced indica a partir de quina versió de la plataforma especificada la declaració va ser introduïda
@Deprecated indica la primera versió de la plataforma especificada en què la declaració està desfasada.
@Obsoleted Indica la primera versió de la plataforma especificada en que la declaració és obsoleta. Quan una declaració és obsoleta s’elimina de la plataforma i ja no pot ser utilitzada.
@Message Servei per mostrar un missatge textual que es mostra al fer la compilació o per alertar d’un error de l’ús d’una declaració que està obsoleta o desfasada. El missatge és un string.
@Renamed S’utilitza per mostrar un missatge textual que indica el nou nom d’una declaració que ha estat reanomenada. El nou nom es mostra al compilador quan s’emet un error per el canvi de nom de la declaració. El nou nom es un string.
@testable Aplicar aquest atribut per importar les declaracions de mòduls compilats amb el l'opció de test activat, de mode que es pot accedir a qualsevol entitat marcada amb nivell de modificació intern, tal i com si haguessin estat declats com a nivell de modificació públic.
@warn_unused_result S'utilitza perque el compilador emeti un warning quan el mètode o funció és cridat sense utilitzar el seu resultat.

Gestió de memoria

modifica

Proveeix una solució automàtica a la gestió de memòria. En la majoria dels casos el procés d'alliberar memòria ha de pertànyer a la lògica de les aplicacions. Això és típic per a la memòria que ha estat usada per a crear apilaments (piles - heap) en Java, aquests casos es pot veure en constants per gestió de pools i en les àrees dels mètodes. La pila (heap) és una part de la memòria on els objectes de Java viuen, i aquesta és l'única part de la memòria que es veu d'alguna manera involucrada en el procés de recol·lecció del garbage collector. Tot el garbage collector gira entorn a assegurar que la pila (heap) de memòria sempre estigui alliberat tant espai com sigui possible. El propòsit del garbage collector és trobar i eliminar objectes que no es puguin assolir.

Està a càrrec de la JVM (Java Virtual Machine), l'experiència indica que quan els programes fan una petició al garbage collector, la JVM sol concedir aquesta petició a ser atesa en una manera primerenca, però no és garantia que això es compleixi . En general es diu que el Garbage Collector, pensa per si sol i s'executa quan ell ho desitja.

Cada programa fet en Java té un o més fils, on cada un d'aquests és propietari de la seva part a la pila de la memòria. Un objecte és elegible pel garbage collector, quan no es pugui accedir-hi (a través del seu fil), això és que no té una variable de referència accessible que apunti a l'objecte en qüestió. El garbage collector no pot assegurar que sempre hi hagi prou memòria, només que la memòria que hi es serà gestionada al més eficientment possible.

class MyClass {
            public static void main(String[] args) {
                        MyClass myObject;
                        myObject = new MyClass(); //Primer objecte
                        myObject = new MyClass(); //Segon objecte
            }
}
 
Moment de fer un nou "new". Image de http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html

Tip: Només s'assigna el primer ja que 1 punter no pot apuntar a 2 llocs diferents.

És un procés de baixa prioritat, pel que no es passa en tot moment alliberant memòria, sinó que passa de tant en tant, que podria ser en un temps mort del processador, encara que també nosaltres podríem suggerir-li que passi, però passarà quan pugui i vulgui, un parell d'exemples de com enviar cridar son aquests:

System.gc();
/* o */
Runtime.getRuntime().gc();
class MyClass {
    public static void main(String[] args) {
        MyClass myFirstObject = new MyClass();
        MyClass mySecondObject = new MyClass();
        myFirstObject = mySecondObject;
        mySecondObject = null;
    }
}

Procés:

  1. Es crea el primer objecte en el heap, es crea la primera referència al stack, i la referència apunta a l'objecte.
  2. Es crea el segon objecte en el heap, es crea la segona referència al stack, i la referència apunta a l'objecte.
  3. La primera referència apunta cap al segon objecte. En aquest moment el primer objecte es queda sense referència, és rebutjat pel GC, i s'allibera memoria.
  4. El segon objecte apunta a res.
class MyClass {
    public MyClass myProperty;
    public static void main(String[] args) {
        MyClass myFirstObject = new MyClass();
        myFirstObject.myProperty = new MyClass();
        myFirstObject = null;
    }
}

Procés:

  1. Es crea una MyClass anomenada myProperty en el stack.
  2. Es crea el primer objecte en el heap, es crea la primera referència al stack, i la referència apunta a l'objecte.
  3. Es crea el segon objecte en el heap, es crea la segona referència al stack, i la referència apunta a l'objects, com a atribut.
  4. La primera referència apunta a res. En aquest moment el primer objecte es queda sense referència, és rebutjat pel GC, i s'allibera memoria. Per tant alhora es buida tota propietat.

No quedaria cap element en el heap.

Island of Isolation
modifica

Els objectes tenen referències cap a ells, però no són accessibles aquests objectes per al programador, és a dir, no tenim referències dels objectes, i queden aïllats per al seu ús.

class MyClass {
    public MyClass myProperty;
    public static void main(String[] args) {
        MyClass myFirstObject = new MyClass();
        MyClass mySecondObject = new MyClass();
        myFirstObject.myProperty = mySecondObject;
        mySecondObject.myProperty = myFirstObject;
        mySecondObject = null;
        myFirstObject = null;
    }
}

Procés:

  1. Es crea una MyClass anomenada myProperty en el stack.
  2. Es crea el primer objecte en el heap, es crea la primera referència al stack, i la referència apunta a l'objecte.
  3. Es crea el segon objecte en el heap, es crea la segona referència al stack, i la referència apunta a l'objecte.
  4. Ara myProperty de la referència myFirstObject apunta cap a l'objecte de mySecondObject.
  5. Ara myProperty de la referència myFirstObject apunta cap a l'objecte de mySecondObject. Recordem que myFirstObject apunta a mySecondObject.
  6. mySeconObject apunta a res.
  7. myFirstObject apunta a res.

¿Quin problema hi ha? Que ara els punters originals no apunten a res i no hi ha referències al stack. No hi ha una mínima connexió amb les referències del stack, quan un objecte no té encara que sigui una referència indirecta amb el stack, és candidat perquè el GarbageCollector l'elimini en el seu següent passat.

Per tant quedaria així:

  1. myFirstObject -> Null (stack)
  2. mySecondObject -> Null (stack)
  3. myFirstObject.myProperty -> mySecondObject(heap)
  4. mySecondObject.myProperty -> myFirstObject(heap)
Eines de control
modifica
public class MyClass {
    String id;
    protected void finalize(){
        System.out.println(this.id); //id atribut de la class referenciada.
    }
    /* Tractament d'alguns dels casos anteriors.
    */
}

Abans d'executar-se el GarbageColler per esborrar del heap l'objecte executa finalize(), per poder veure quins objectes toca esborrar.

ARC (Automatic Reference Counting)
modifica

Swift utilitza un mecanisme automàtic anomenat (ARC) que fa un seguiment i gestiona l´ús de memòria de l’aplicació. En la majoria dels casos, no cal preocupar-se per la gestió de memòria, doncs l’ARC la allibera automàticament la memòria utilitzada per una instància d’una classe quan ja no es necessita.

De totes formes, en alguns casos l’ARC necessita informació sobre la relació entre diferents parts del teu codi, per tal de poder fer la gestió automàticament. A continuació es descriuen aquests casos i es mostra com habilitar l’ARC perquè faci la gestió automàtica.

Nota: El comptatge de referències només s’aplica a les classes. Les estructures i les enumeracions són de tipus valor i no tipus referència, i no son emmagatzemades ni passades per referència.

Funcionament de l’ARC
modifica

Quan es crea una nova instància duna classe l’ARC reserva un espai de memòria per emmagatzemar aquesta instància. Aquest espai de memòria guarda informació sobre el tipus d’instància i els valors que emmagatzemen les propietats d’aquesta. En el moment en què la instància ja no es necessita, l’ARC allibera la memòria. Si s’intentés accedir a una instància que l’ARC ja ha eliminat, l’aplicació donarà error.

Perquè això no passi, es fa un seguiment de quantes propietats, constants i variables fan referència a la instància en qüestió, l’ARC no alliberarà l’espai utilitzat per la instància mentre hi hagi alguna referència cap aquella instància.

Per aquest motiu, quan s’assigna una instància duna classe a una propietat, constant o variable, es crea una strong reference cap aquella instància. El lligam es diu que és fort, perquè mentre existeixi la referència, la instància no s’eliminarà.

Creació d'Strong reference
modifica

Partint d’aquesta classe

class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("\(name) is being initialized")
	}
	deinit {
        print("\(name) is being deinitialized")
    }}

Si fem:

var reference1: Person?

La variable reference1 apunta nil. Pero si fem:

reference1 = Person(name: "John Appleseed")
// prints "John Appleseed is being initialized"

Es crea una strong reference entre reference 1 i la instància de Person. Com que hi ha almenys una strong reference, l’ARC s’assegura que aquesta instància de Person es mantingui en memòria. Es poden crear tantes strong reference cap a la mateixa instància com es vulgui.

reference2 = reference1
reference3 = reference1

Mentre que la instància de Person tingui algun strong reference, no s’eliminara excepte si fem que totes apuntin a nil.

reference3 = nil
// prints "John Appleseed is being deinitialized"

Finalment s’eliminaria l'strong reference.

 
exemple strong reference
Strong Reference Cycles entre Class Instances
modifica

En els exemples anteriors l’ARC és capaç de fer un seguiment del nombre de referencies de la instància Person, però és possible escriure un codi en el que una instància d’una class mai arribi a tenir zero referències. Això pot passar quan dues instàncies de classes tenen una strong reference entre elles, de mode que es mantenen vives mútuament. Aquest fet es coneix com a strong reference cycle.

 
Exemple strong reference cycle

L’Strong reference cycle es pot resoldre declarant les referencies com a weak or unowned en comptes d’strong references.

Weak References
modifica

S’ha d’utilitzar aquest tipus de referència per evitar els reference cycles sempre que sigui possible que hi hagi una referència sense valor en algun moment de la vida de l’objecte.

 
exemple weak reference

A l'exemple de la imatge, s'elimina la referencia de john a la instància de persona, per tan ja no hi ha cap strong reference.

 
exmple eliminacio strong reference amb weak reference

En aquest cas, també s'elimina la strong reference de unit4A cap a la instància de Apartment, i com que Apartment té una weak reference sobre la instància de Person, s'eliminen les dues instàncies.

 
exmple eliminacio weak reference
Unowned reference
modifica

Les unowned references no creen un strong hold a la instaàcia que es refereixen, però s’assumeix que sempre tindrà un valor, i per tant no es un tipus opcional.

 
exemple unowned reference

En cas d'eliminar la strong reference de john cap a la instància de Customer, com que no queda cap strong reference cap a la instància i la de credit car no pot estar buida, s'eliminen les dues instàncies.

 
exemple eliminació unowned reference

Resum diferències

modifica
Imports
modifica
  • Java
import package.ClassName
  • Swift
import framework
Herència
modifica
  • Java
class Fill extends Pare
  • Swift
class Fill:Pare
Herència múltiple
modifica
  • Java
class Fill extends Pare implements I
  • Swift
class Fill:Pare,I


Interfícies
modifica
  • Java
interface A
  • Swift
protocol A
Variables
modifica
  • Java
int Variable
  • Swift
var Variable: Int
Constructors
modifica
  • Java
A()
  • Swift
init()
Creació d'objectes
modifica
  • Java
Objecte obj = new Objecte();
  • Swift
var obj : Objecte = Objecte()
Mètodes
modifica
Declaració
modifica
  • Java
void FesAlgunaCosa(String arg)
  • Swift
func FesAlgunaCosa(arg: String) -> void
  • Java
Objecte.FesAlgunaCosa(arg)
  • Swift
Objecte.FesAlgunaCosa(arg)